Reactive type checks for all argument method resolvers

All method argument resolvers now explicitly check for the presence
of a reactive type wrapper and reject it where not expected.

Issue: SPR-15297
This commit is contained in:
Rossen Stoyanchev
2017-03-14 19:55:08 -04:00
parent a04fef8450
commit 164204ca04
41 changed files with 659 additions and 278 deletions

View File

@@ -25,11 +25,13 @@ import reactor.test.StepVerifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebInputException;
@@ -53,6 +55,7 @@ public class CookieValueMethodArgumentResolverTests {
private MethodParameter cookieParameter;
private MethodParameter cookieStringParameter;
private MethodParameter stringParameter;
private MethodParameter cookieMonoParameter;
@Before
@@ -60,14 +63,16 @@ public class CookieValueMethodArgumentResolverTests {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.request = MockServerHttpRequest.get("/").build();
this.bindingContext = new BindingContext();
Method method = getClass().getMethod("params", HttpCookie.class, String.class, String.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
this.cookieParameter = new SynthesizingMethodParameter(method, 0);
this.cookieStringParameter = new SynthesizingMethodParameter(method, 1);
this.stringParameter = new SynthesizingMethodParameter(method, 2);
this.cookieMonoParameter = new SynthesizingMethodParameter(method, 3);
}
@@ -75,7 +80,20 @@ public class CookieValueMethodArgumentResolverTests {
public void supportsParameter() {
assertTrue(this.resolver.supportsParameter(this.cookieParameter));
assertTrue(this.resolver.supportsParameter(this.cookieStringParameter));
}
@Test
public void doesNotSupportParameter() {
assertFalse(this.resolver.supportsParameter(this.stringParameter));
try {
this.resolver.supportsParameter(this.cookieMonoParameter);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"CookieValueMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -128,7 +146,8 @@ public class CookieValueMethodArgumentResolverTests {
public void params(
@CookieValue("name") HttpCookie cookie,
@CookieValue(name = "name", defaultValue = "bar") String cookieString,
String stringParam) {
String stringParam,
@CookieValue Mono<String> monoCookie) {
}
}

View File

@@ -38,6 +38,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link ErrorsMethodArgumentResolver}.
@@ -78,12 +79,24 @@ public class ErrorsArgumentResolverTests {
parameter = this.testMethod.arg(BindingResult.class);
assertTrue(this.resolver.supportsParameter(parameter));
}
parameter = this.testMethod.arg(ResolvableType.forClassWithGenerics(Mono.class, Errors.class));
@Test
public void doesNotSupport() throws Exception {
MethodParameter parameter = this.testMethod.arg(String.class);
assertFalse(this.resolver.supportsParameter(parameter));
parameter = this.testMethod.arg(String.class);
assertFalse(this.resolver.supportsParameter(parameter));
try {
parameter = this.testMethod.arg(ResolvableType.forClassWithGenerics(Mono.class, Errors.class));
assertFalse(this.resolver.supportsParameter(parameter));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ErrorsMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test

View File

@@ -25,9 +25,11 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@@ -47,27 +49,43 @@ public class ExpressionValueMethodArgumentResolverTests {
private MethodParameter paramSystemProperty;
private MethodParameter paramNotSupported;
private MethodParameter paramAlsoNotSupported;
@Before
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
Method method = getClass().getMethod("params", int.class, String.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
this.paramSystemProperty = new MethodParameter(method, 0);
this.paramNotSupported = new MethodParameter(method, 1);
this.paramAlsoNotSupported = new MethodParameter(method, 2);
}
@Test
public void supportsParameter() throws Exception {
assertTrue(this.resolver.supportsParameter(this.paramSystemProperty));
}
@Test
public void doesNotSupport() throws Exception {
assertFalse(this.resolver.supportsParameter(this.paramNotSupported));
try {
this.resolver.supportsParameter(this.paramAlsoNotSupported);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ExpressionValueMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -90,7 +108,10 @@ public class ExpressionValueMethodArgumentResolverTests {
@SuppressWarnings("unused")
public void params(@Value("#{systemProperties.systemProperty}") int param1, String notSupported) {
public void params(
@Value("#{systemProperties.systemProperty}") int param1,
String notSupported,
@Value("#{systemProperties.foo}") Mono<String> alsoNotSupported) {
}
}

View File

@@ -34,6 +34,7 @@ import rx.RxReactiveStreams;
import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.HttpEntity;
@@ -44,14 +45,19 @@ import org.springframework.http.codec.HttpMessageReader;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.ObjectUtils;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.*;
import static org.springframework.core.ResolvableType.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
/**
* Unit tests for {@link HttpEntityArgumentResolver}.When adding a test also
@@ -78,7 +84,7 @@ public class HttpEntityArgumentResolverTests {
private HttpEntityArgumentResolver createResolver() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new HttpEntityArgumentResolver(readers);
return new HttpEntityArgumentResolver(readers, new ReactiveAdapterRegistry());
}
@@ -105,6 +111,15 @@ public class HttpEntityArgumentResolverTests {
public void doesNotSupport() throws Exception {
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(Mono.class, String.class)));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
try {
this.resolver.supportsParameter(this.testMethod.arg(Mono.class, httpEntityType(String.class)));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"HttpEntityArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -348,6 +363,7 @@ public class HttpEntityArgumentResolverTests {
HttpEntity<io.reactivex.Observable<String>> rxJava2ObservableBody,
HttpEntity<Flowable<String>> flowableBody,
HttpEntity<CompletableFuture<String>> completableFutureBody,
RequestEntity<String> requestEntity) {}
RequestEntity<String> requestEntity,
Mono<HttpEntity<String>> httpEntityMono) {}
}

View File

@@ -25,6 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
@@ -112,7 +113,8 @@ public class InitBinderBindingContextTests {
@Test
public void createBinderTypeConversion() throws Exception {
this.request = MockServerHttpRequest.get("/path?requestParam=22").build();
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(null, false));
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(null, adapterRegistry, false));
BindingContext context = createBindingContext("initBinderTypeConversion", WebDataBinder.class, int.class);
WebDataBinder dataBinder = context.createDataBinder(createExchange(), null, "foo");

View File

@@ -281,7 +281,7 @@ public class ModelAttributeMethodArgumentResolverTests {
private ModelAttributeMethodArgumentResolver createResolver() {
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry());
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry(), false);
}
private ServerWebExchange exchange(String formData) throws URISyntaxException {

View File

@@ -16,6 +16,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -120,14 +121,17 @@ public class ModelInitializerTests {
private List<InvocableHandlerMethod> getAttributeMethods(Object controller) {
return MethodIntrospector
.selectMethods(controller.getClass(), ATTRIBUTE_METHODS).stream()
.map(method -> {
InvocableHandlerMethod invocable = new InvocableHandlerMethod(controller, method);
invocable.setArgumentResolvers(Collections.singletonList(new ModelArgumentResolver()));
return invocable;
})
.map(method -> toInvocable(controller, method))
.collect(Collectors.toList());
}
private InvocableHandlerMethod toInvocable(Object controller, Method method) {
ModelArgumentResolver resolver = new ModelArgumentResolver(new ReactiveAdapterRegistry());
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(controller, method);
handlerMethod.setArgumentResolvers(Collections.singletonList(resolver));
return handlerMethod;
}
@SuppressWarnings("unused")
private static class TestController {

View File

@@ -26,9 +26,11 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerMapping;
@@ -38,6 +40,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link PathVariableMapMethodArgumentResolver}.
@@ -53,19 +56,21 @@ public class PathVariableMapMethodArgumentResolverTests {
private MethodParameter paramMap;
private MethodParameter paramNamedMap;
private MethodParameter paramMapNoAnnot;
private MethodParameter paramMonoMap;
@Before
public void setup() throws Exception {
this.resolver = new PathVariableMapMethodArgumentResolver();
this.resolver = new PathVariableMapMethodArgumentResolver(new ReactiveAdapterRegistry());
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
Method method = getClass().getMethod("handle", Map.class, Map.class, Map.class);
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
this.paramMap = new MethodParameter(method, 0);
this.paramNamedMap = new MethodParameter(method, 1);
this.paramMapNoAnnot = new MethodParameter(method, 2);
this.paramMonoMap = new MethodParameter(method, 3);
}
@@ -74,6 +79,15 @@ public class PathVariableMapMethodArgumentResolverTests {
assertTrue(resolver.supportsParameter(paramMap));
assertFalse(resolver.supportsParameter(paramNamedMap));
assertFalse(resolver.supportsParameter(paramMapNoAnnot));
try {
this.resolver.supportsParameter(this.paramMonoMap);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"PathVariableMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -102,7 +116,8 @@ public class PathVariableMapMethodArgumentResolverTests {
public void handle(
@PathVariable Map<String, String> map,
@PathVariable(value = "name") Map<String, String> namedMap,
Map<String, String> mapWithoutAnnotat) {
Map<String, String> mapWithoutAnnotat,
@PathVariable Mono<Map<?, ?>> monoMap) {
}
}

View File

@@ -27,6 +27,7 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -44,6 +45,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Unit tests for {@link PathVariableMethodArgumentResolver}.
@@ -58,17 +60,15 @@ public class PathVariableMethodArgumentResolverTests {
private ServerWebExchange exchange;
private MethodParameter paramNamedString;
private MethodParameter paramString;
private MethodParameter paramNotRequired;
private MethodParameter paramOptional;
private MethodParameter paramMono;
@Before
public void setup() throws Exception {
this.resolver = new PathVariableMethodArgumentResolver(null);
this.resolver = new PathVariableMethodArgumentResolver(null, new ReactiveAdapterRegistry());
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
@@ -78,6 +78,7 @@ public class PathVariableMethodArgumentResolverTests {
paramString = new SynthesizingMethodParameter(method, 1);
paramNotRequired = new SynthesizingMethodParameter(method, 2);
paramOptional = new SynthesizingMethodParameter(method, 3);
paramMono = new SynthesizingMethodParameter(method, 4);
}
@@ -85,6 +86,15 @@ public class PathVariableMethodArgumentResolverTests {
public void supportsParameter() {
assertTrue(this.resolver.supportsParameter(this.paramNamedString));
assertFalse(this.resolver.supportsParameter(this.paramString));
try {
this.resolver.supportsParameter(this.paramMono);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"PathVariableMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -161,10 +171,13 @@ public class PathVariableMethodArgumentResolverTests {
}
@SuppressWarnings("unused")
public void handle(@PathVariable(value = "name") String param1, String param2,
@SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"})
public void handle(
@PathVariable(value = "name") String param1,
String param2,
@PathVariable(name = "name", required = false) String param3,
@PathVariable("name") Optional<String> param4) {
@PathVariable("name") Optional<String> param4,
@PathVariable Mono<String> param5) {
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -61,7 +62,8 @@ public class RequestAttributeMethodArgumentResolverTests {
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
ServerHttpRequest request = MockServerHttpRequest.get("/").build();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse());
@@ -74,6 +76,15 @@ public class RequestAttributeMethodArgumentResolverTests {
public void supportsParameter() throws Exception {
assertTrue(this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 0)));
assertFalse(this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 4)));
try {
this.resolver.supportsParameter(new MethodParameter(this.handleMethod, 5));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestAttributeMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -151,7 +162,8 @@ public class RequestAttributeMethodArgumentResolverTests {
@RequestAttribute("specialFoo") Foo namedFoo,
@RequestAttribute(name="foo", required = false) Foo notRequiredFoo,
@RequestAttribute(name="foo") Optional<Foo> optionalFoo,
String notSupported) {
String notSupported,
@RequestAttribute Mono<Foo> alsoNotSupported) {
}

View File

@@ -32,6 +32,7 @@ import rx.RxReactiveStreams;
import rx.Single;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
@@ -69,7 +70,7 @@ public class RequestBodyArgumentResolverTests {
public void setup() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
this.resolver = new RequestBodyArgumentResolver(readers);
this.resolver = new RequestBodyArgumentResolver(readers, new ReactiveAdapterRegistry());
}

View File

@@ -25,6 +25,7 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -32,6 +33,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@@ -52,18 +54,21 @@ public class RequestHeaderMapMethodArgumentResolverTests {
private MethodParameter paramMultiValueMap;
private MethodParameter paramHttpHeaders;
private MethodParameter paramUnsupported;
private MethodParameter paramAlsoUnsupported;
@Before
public void setup() throws Exception {
resolver = new RequestHeaderMapMethodArgumentResolver();
resolver = new RequestHeaderMapMethodArgumentResolver(new ReactiveAdapterRegistry());
request = MockServerHttpRequest.get("/").build();
Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, HttpHeaders.class, Map.class);
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
paramMap = new SynthesizingMethodParameter(method, 0);
paramMultiValueMap = new SynthesizingMethodParameter(method, 1);
paramHttpHeaders = new SynthesizingMethodParameter(method, 2);
paramUnsupported = new SynthesizingMethodParameter(method, 3);
paramUnsupported = new SynthesizingMethodParameter(method, 3);
paramAlsoUnsupported = new SynthesizingMethodParameter(method, 4);
}
@@ -73,6 +78,15 @@ public class RequestHeaderMapMethodArgumentResolverTests {
assertTrue("MultiValueMap parameter not supported", resolver.supportsParameter(paramMultiValueMap));
assertTrue("HttpHeaders parameter not supported", resolver.supportsParameter(paramHttpHeaders));
assertFalse("non-@RequestParam map supported", resolver.supportsParameter(paramUnsupported));
try {
this.resolver.supportsParameter(this.paramAlsoUnsupported);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestHeaderMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -132,10 +146,12 @@ public class RequestHeaderMapMethodArgumentResolverTests {
@SuppressWarnings("unused")
public void params(@RequestHeader Map<?, ?> param1,
@RequestHeader MultiValueMap<?, ?> param2,
@RequestHeader HttpHeaders param3,
Map<?,?> unsupported) {
public void params(
@RequestHeader Map<?, ?> param1,
@RequestHeader MultiValueMap<?, ?> param2,
@RequestHeader HttpHeaders param3,
Map<?,?> unsupported,
@RequestHeader Mono<Map<?, ?>> alsoUnsupported) {
}
}

View File

@@ -29,6 +29,7 @@ import reactor.test.StepVerifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -64,13 +65,15 @@ public class RequestHeaderMethodArgumentResolverTests {
private MethodParameter paramNamedValueMap;
private MethodParameter paramDate;
private MethodParameter paramInstant;
private MethodParameter paramMono;
@Before
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.request = MockServerHttpRequest.get("/").build();
@@ -87,6 +90,7 @@ public class RequestHeaderMethodArgumentResolverTests {
this.paramNamedValueMap = new SynthesizingMethodParameter(method, 5);
this.paramDate = new SynthesizingMethodParameter(method, 6);
this.paramInstant = new SynthesizingMethodParameter(method, 7);
this.paramMono = new SynthesizingMethodParameter(method, 8);
}
@@ -95,6 +99,15 @@ public class RequestHeaderMethodArgumentResolverTests {
assertTrue("String parameter not supported", resolver.supportsParameter(paramNamedDefaultValueStringHeader));
assertTrue("String array parameter not supported", resolver.supportsParameter(paramNamedValueStringArray));
assertFalse("non-@RequestParam parameter supported", resolver.supportsParameter(paramNamedValueMap));
try {
this.resolver.supportsParameter(this.paramMono);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestHeaderMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -237,7 +250,8 @@ public class RequestHeaderMethodArgumentResolverTests {
@RequestHeader("${systemProperty}") String param5,
@RequestHeader("name") Map<?, ?> unsupported,
@RequestHeader("name") Date dateParam,
@RequestHeader("name") Instant instantParam) {
@RequestHeader("name") Instant instantParam,
@RequestHeader Mono<String> alsoNotSupported) {
}
}

View File

@@ -23,8 +23,10 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
@@ -37,6 +39,7 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.web.method.MvcAnnotationPredicates.requestParam;
/**
@@ -52,7 +55,7 @@ public class RequestParamMapMethodArgumentResolverTests {
@Before
public void setup() throws Exception {
this.resolver = new RequestParamMapMethodArgumentResolver();
this.resolver = new RequestParamMapMethodArgumentResolver(new ReactiveAdapterRegistry());
}
@@ -69,6 +72,17 @@ public class RequestParamMapMethodArgumentResolverTests {
param = this.testMethod.annotNotPresent(RequestParam.class).arg(Map.class);
assertFalse(this.resolver.supportsParameter(param));
try {
param = this.testMethod.annot(requestParam()).arg(Mono.class, Map.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMapMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -120,7 +134,8 @@ public class RequestParamMapMethodArgumentResolverTests {
@RequestParam Map<?, ?> param1,
@RequestParam MultiValueMap<?, ?> param2,
@RequestParam("name") Map<?, ?> param3,
Map<?, ?> param4) {
Map<?, ?> param4,
@RequestParam Mono<Map<?, ?>> paramMono) {
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
@@ -26,12 +27,14 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.method.MvcAnnotationPredicates;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
@@ -43,6 +46,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.web.method.MvcAnnotationPredicates.requestParam;
@@ -63,7 +67,8 @@ public class RequestParamMethodArgumentResolverTests {
@Before
public void setup() throws Exception {
this.resolver = new RequestParamMethodArgumentResolver(null, true);
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestParamMethodArgumentResolver(null, adapterRegistry, true);
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
@@ -73,7 +78,6 @@ public class RequestParamMethodArgumentResolverTests {
@Test
public void supportsParameter() {
this.resolver = new RequestParamMethodArgumentResolver(null, true);
MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class);
assertTrue(this.resolver.supportsParameter(param));
@@ -96,11 +100,42 @@ public class RequestParamMethodArgumentResolverTests {
param = this.testMethod.annot(requestParam().notRequired()).arg(String.class);
assertTrue(this.resolver.supportsParameter(param));
param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class);
this.resolver = new RequestParamMethodArgumentResolver(null, false);
}
@Test
public void doesNotSupportParameterWithDefaultResolutionTurnedOff() {
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new RequestParamMethodArgumentResolver(null, adapterRegistry, false);
MethodParameter param = this.testMethod.annotNotPresent(RequestParam.class).arg(String.class);
assertFalse(this.resolver.supportsParameter(param));
}
@Test
public void doesNotSupportReactiveWrapper() {
MethodParameter param;
try {
param = this.testMethod.annot(requestParam()).arg(Mono.class, String.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMethodArgumentResolver doesn't support reactive type wrapper"));
}
try {
param = this.testMethod.annotNotPresent(RequestParam.class).arg(Mono.class, String.class);
this.resolver.supportsParameter(param);
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"RequestParamMethodArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
public void resolveWithQueryString() throws Exception {
MethodParameter param = this.testMethod.annot(requestParam().notRequired("bar")).arg(String.class);
@@ -208,7 +243,7 @@ public class RequestParamMethodArgumentResolverTests {
}
private Object resolve(MethodParameter parameter, ServerWebExchange exchange) {
return this.resolver.resolveArgument(parameter, this.bindContext, exchange).blockMillis(0);
return this.resolver.resolveArgument(parameter, this.bindContext, exchange).block(Duration.ZERO);
}
@@ -219,6 +254,7 @@ public class RequestParamMethodArgumentResolverTests {
@RequestParam("name") Map<?, ?> param3,
@RequestParam Map<?, ?> param4,
String stringNotAnnot,
Mono<String> monoStringNotAnnot,
@RequestParam("name") String paramRequired,
@RequestParam(name = "name", required = false) String paramNotRequired,
@RequestParam("name") Optional<Integer> paramOptional,

View File

@@ -21,6 +21,7 @@ import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -43,7 +44,8 @@ import static org.mockito.Mockito.*;
*/
public class ServerWebExchangeArgumentResolverTests {
private final ServerWebExchangeArgumentResolver resolver = new ServerWebExchangeArgumentResolver();
private final ServerWebExchangeArgumentResolver resolver =
new ServerWebExchangeArgumentResolver(new ReactiveAdapterRegistry());
private ServerWebExchange exchange;
@@ -67,6 +69,15 @@ public class ServerWebExchangeArgumentResolverTests {
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ServerHttpResponse.class)));
assertTrue(this.resolver.supportsParameter(this.testMethod.arg(HttpMethod.class)));
assertFalse(this.resolver.supportsParameter(this.testMethod.arg(String.class)));
try {
this.resolver.supportsParameter(this.testMethod.arg(Mono.class, ServerWebExchange.class));
fail();
}
catch (IllegalStateException ex) {
assertTrue("Unexpected error message:\n" + ex.getMessage(),
ex.getMessage().startsWith(
"ServerWebExchangeArgumentResolver doesn't support reactive type wrapper"));
}
}
@Test
@@ -91,7 +102,8 @@ public class ServerWebExchangeArgumentResolverTests {
ServerHttpResponse response,
WebSession session,
HttpMethod httpMethod,
String s) {
String s,
Mono<ServerWebExchange> monoExchange) {
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
@@ -44,8 +45,14 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link SessionAttributeMethodArgumentResolver}.
@@ -67,7 +74,8 @@ public class SessionAttributeMethodArgumentResolverTests {
public void setup() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory());
ReactiveAdapterRegistry adapterRegistry = new ReactiveAdapterRegistry();
this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory(), adapterRegistry);
this.session = mock(WebSession.class);
WebSessionManager sessionManager = new MockWebSessionManager(this.session);

View File

@@ -3,6 +3,7 @@ package org.springframework.web.reactive.result.method.annotation
import org.junit.Before
import org.junit.Test
import org.springframework.core.MethodParameter
import org.springframework.core.ReactiveAdapterRegistry
import org.springframework.core.annotation.SynthesizingMethodParameter
import org.springframework.format.support.DefaultFormattingConversionService
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest
@@ -34,7 +35,7 @@ class RequestParamMethodArgumentResolverKotlinTests {
@Before
fun setup() {
this.resolver = RequestParamMethodArgumentResolver(null, true)
this.resolver = RequestParamMethodArgumentResolver(null, ReactiveAdapterRegistry(), true)
this.request = MockServerHttpRequest.get("/").build()
val initializer = ConfigurableWebBindingInitializer()
initializer.conversionService = DefaultFormattingConversionService()