Replace direct use of Validator and ConversionService

This commit replaces direct use of Validator and ConversionService in
the reactive @RequestMapping infrustructure in favor of using the
BindingContext.

Issue: SPR-14541
This commit is contained in:
Rossen Stoyanchev
2016-10-11 20:16:03 -04:00
parent d87aa40efe
commit 8a043ae9aa
25 changed files with 208 additions and 249 deletions

View File

@@ -48,7 +48,6 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
import org.springframework.web.bind.WebExchangeDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
@@ -155,20 +154,17 @@ public class WebReactiveConfigurationTests {
assertHasMessageReader(readers, TestBean.class, APPLICATION_JSON);
assertHasMessageReader(readers, TestBean.class, null);
name = "webReactiveConversionService";
ConversionService service = context.getBean(name, ConversionService.class);
assertSame(service, adapter.getConversionService());
name = "webReactiveValidator";
Validator validator = context.getBean(name, Validator.class);
assertSame(validator, adapter.getValidator());
assertEquals(OptionalValidatorFactoryBean.class, validator.getClass());
WebBindingInitializer bindingInitializer = adapter.getWebBindingInitializer();
assertNotNull(bindingInitializer);
WebExchangeDataBinder binder = new WebExchangeDataBinder(new Object());
bindingInitializer.initBinder(binder);
name = "webReactiveConversionService";
ConversionService service = context.getBean(name, ConversionService.class);
assertSame(service, binder.getConversionService());
name = "webReactiveValidator";
Validator validator = context.getBean(name, Validator.class);
assertSame(validator, binder.getValidator());
}

View File

@@ -25,13 +25,11 @@ import reactor.core.publisher.Mono;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.tests.TestSubscriber;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.reactive.result.method.BindingContext;
@@ -67,8 +65,7 @@ public class CookieValueMethodArgumentResolverTests {
public void setUp() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ConversionService cs = new DefaultConversionService();
this.resolver = new CookieValueMethodArgumentResolver(cs, context.getBeanFactory());
this.resolver = new CookieValueMethodArgumentResolver(context.getBeanFactory());
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();

View File

@@ -25,12 +25,10 @@ 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.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@@ -58,10 +56,9 @@ public class ExpressionValueMethodArgumentResolverTests {
@Before
public void setUp() throws Exception {
ConversionService conversionService = new GenericConversionService();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new ExpressionValueMethodArgumentResolver(conversionService, context.getBeanFactory());
this.resolver = new ExpressionValueMethodArgumentResolver(context.getBeanFactory());
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();

View File

@@ -46,7 +46,6 @@ 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.tests.TestSubscriber;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
@@ -59,7 +58,6 @@ 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.mockito.Mockito.mock;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
/**
@@ -91,7 +89,7 @@ public class HttpEntityArgumentResolverTests {
private HttpEntityArgumentResolver createResolver() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new HttpEntityArgumentResolver(readers, mock(Validator.class));
return new HttpEntityArgumentResolver(readers);
}

View File

@@ -49,8 +49,10 @@ import org.springframework.tests.TestSubscriber;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
@@ -76,6 +78,8 @@ public class MessageReaderArgumentResolverTests {
private MockServerHttpRequest request;
private BindingContext bindingContext;
private ResolvableMethod testMethod = ResolvableMethod.onClass(this.getClass()).name("handle");
@@ -84,6 +88,10 @@ public class MessageReaderArgumentResolverTests {
this.request = new MockServerHttpRequest(HttpMethod.POST, "/path");
MockServerHttpResponse response = new MockServerHttpResponse();
this.exchange = new DefaultServerWebExchange(this.request, response, new MockWebSessionManager());
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setValidator(new TestBeanValidator());
this.bindingContext = new BindingContext(initializer);
}
@@ -92,7 +100,7 @@ public class MessageReaderArgumentResolverTests {
this.request.setBody("{\"bar\":\"BARBAR\",\"foo\":\"FOOFOO\"}");
ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class);
MethodParameter param = this.testMethod.resolveParam(type);
Mono<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> result = this.resolver.readBody(param, true, this.bindingContext, this.exchange);
TestSubscriber.subscribe(result)
.assertError(UnsupportedMediaTypeStatusException.class);
@@ -105,7 +113,8 @@ public class MessageReaderArgumentResolverTests {
this.request.setHeader("Content-Type", "application/json");
ResolvableType type = forClassWithGenerics(Mono.class, TestBean.class);
MethodParameter param = this.testMethod.resolveParam(type);
Mono<TestBean> result = (Mono<TestBean>) this.resolver.readBody(param, true, this.exchange).block();
Mono<TestBean> result = (Mono<TestBean>) this.resolver.readBody(
param, true, this.bindingContext, this.exchange).block();
TestSubscriber.subscribe(result).assertError(ServerWebInputException.class);
}
@@ -285,7 +294,7 @@ public class MessageReaderArgumentResolverTests {
@SuppressWarnings("unchecked")
private <T> T resolveValue(MethodParameter param, String body) {
this.request.setHeader("Content-Type", "application/json").setBody(body);
Mono<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> result = this.resolver.readBody(param, true, this.bindingContext, this.exchange);
Object value = result.block(Duration.ofSeconds(5));
assertNotNull(value);
@@ -299,7 +308,7 @@ public class MessageReaderArgumentResolverTests {
private AbstractMessageReaderArgumentResolver resolver(Decoder<?>... decoders) {
List<HttpMessageReader<?>> readers = new ArrayList<>();
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
return new AbstractMessageReaderArgumentResolver(readers, new TestBeanValidator()) {};
return new AbstractMessageReaderArgumentResolver(readers) {};
}

View File

@@ -27,8 +27,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
@@ -36,6 +35,7 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
import org.springframework.tests.TestSubscriber;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerErrorException;
@@ -71,8 +71,7 @@ public class PathVariableMethodArgumentResolverTests {
@Before
public void setUp() throws Exception {
ConversionService conversionService = new DefaultConversionService();
this.resolver = new PathVariableMethodArgumentResolver(conversionService, null);
this.resolver = new PathVariableMethodArgumentResolver(null);
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();
@@ -122,7 +121,10 @@ public class PathVariableMethodArgumentResolverTests {
uriTemplateVars.put("name", "value");
this.exchange.getAttributes().put(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);
BindingContext bindingContext = new BindingContext();
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
BindingContext bindingContext = new BindingContext(initializer);
Mono<Object> mono = this.resolver.resolveArgument(this.paramOptional, bindingContext, this.exchange);
Object result = mono.block();
assertEquals(Optional.of("value"), result);

View File

@@ -27,15 +27,15 @@ import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.tests.TestSubscriber;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
@@ -69,8 +69,7 @@ public class RequestAttributeMethodArgumentResolverTests {
public void setUp() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ConversionService cs = new DefaultConversionService();
this.resolver = new RequestAttributeMethodArgumentResolver(cs, context.getBeanFactory());
this.resolver = new RequestAttributeMethodArgumentResolver(context.getBeanFactory());
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();
@@ -130,9 +129,13 @@ public class RequestAttributeMethodArgumentResolverTests {
assertEquals(Optional.class, mono.block().getClass());
assertFalse(((Optional) mono.block()).isPresent());
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
BindingContext bindingContext = new BindingContext(initializer);
Foo foo = new Foo();
this.exchange.getAttributes().put("foo", foo);
mono = this.resolver.resolveArgument(param, new BindingContext(), this.exchange);
mono = this.resolver.resolveArgument(param, bindingContext, this.exchange);
assertNotNull(mono.block());
assertEquals(Optional.class, mono.block().getClass());

View File

@@ -39,7 +39,6 @@ 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.tests.TestSubscriber;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.reactive.result.method.BindingContext;
@@ -53,7 +52,6 @@ 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.mockito.Mockito.mock;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
@@ -85,7 +83,7 @@ public class RequestBodyArgumentResolverTests {
private RequestBodyArgumentResolver resolver() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new RequestBodyArgumentResolver(readers, mock(Validator.class));
return new RequestBodyArgumentResolver(readers);
}
@@ -199,7 +197,7 @@ public class RequestBodyArgumentResolverTests {
@SuppressWarnings("unchecked")
private <T> T resolveValue(MethodParameter param, String body) {
this.request.setBody(body);
Mono<Object> result = this.resolver.readBody(param, true, this.exchange);
Mono<Object> result = this.resolver.readBody(param, true, new BindingContext(), this.exchange);
Object value = result.block(Duration.ofSeconds(5));
assertNotNull(value);

View File

@@ -30,15 +30,15 @@ import reactor.core.publisher.Mono;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.tests.TestSubscriber;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
@@ -71,15 +71,14 @@ public class RequestHeaderMethodArgumentResolverTests {
private ServerWebExchange exchange;
private BindingContext bindingContext = new BindingContext();
private BindingContext bindingContext;
@Before
public void setUp() throws Exception {
ConversionService conversionService = new DefaultFormattingConversionService();
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
this.resolver = new RequestHeaderMethodArgumentResolver(conversionService, context.getBeanFactory());
this.resolver = new RequestHeaderMethodArgumentResolver(context.getBeanFactory());
@SuppressWarnings("ConfusingArgumentToVarargsMethod")
Method method = ReflectionUtils.findMethod(getClass(), "params", (Class<?>[]) null);
@@ -95,6 +94,10 @@ public class RequestHeaderMethodArgumentResolverTests {
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
this.bindingContext = new BindingContext(initializer);
}

View File

@@ -29,16 +29,15 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.tests.TestSubscriber;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
@@ -72,13 +71,12 @@ public class RequestParamMethodArgumentResolverTests {
private MethodParameter paramNotRequired;
private MethodParameter paramOptional;
private BindingContext bindingContext = new BindingContext();
private BindingContext bindingContext;
@Before @SuppressWarnings("ConfusingArgumentToVarargsMethod")
public void setUp() throws Exception {
ConversionService conversionService = new DefaultConversionService();
this.resolver = new RequestParamMethodArgumentResolver(conversionService, null, true);
this.resolver = new RequestParamMethodArgumentResolver(null, true);
ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
@@ -96,12 +94,17 @@ public class RequestParamMethodArgumentResolverTests {
this.paramRequired = new SynthesizingMethodParameter(method, 5);
this.paramNotRequired = new SynthesizingMethodParameter(method, 6);
this.paramOptional = new SynthesizingMethodParameter(method, 7);
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
this.bindingContext = new BindingContext(initializer);
}
@Test
public void supportsParameter() {
this.resolver = new RequestParamMethodArgumentResolver(new GenericConversionService(), null, true);
this.resolver = new RequestParamMethodArgumentResolver(null, true);
assertTrue(this.resolver.supportsParameter(this.paramNamedDefaultValueString));
assertTrue(this.resolver.supportsParameter(this.paramNamedStringArray));
assertTrue(this.resolver.supportsParameter(this.paramNamedMap));
@@ -111,7 +114,7 @@ public class RequestParamMethodArgumentResolverTests {
assertTrue(this.resolver.supportsParameter(this.paramNotRequired));
assertTrue(this.resolver.supportsParameter(this.paramOptional));
this.resolver = new RequestParamMethodArgumentResolver(new GenericConversionService(), null, false);
this.resolver = new RequestParamMethodArgumentResolver(null, false);
assertFalse(this.resolver.supportsParameter(this.paramStringNotAnnot));
}

View File

@@ -27,15 +27,15 @@ import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.tests.TestSubscriber;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.result.method.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
@@ -74,8 +74,7 @@ public class SessionAttributeMethodArgumentResolverTests {
public void setUp() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
ConversionService cs = new DefaultConversionService();
this.resolver = new SessionAttributeMethodArgumentResolver(cs, context.getBeanFactory());
this.resolver = new SessionAttributeMethodArgumentResolver(context.getBeanFactory());
this.session = mock(WebSession.class);
when(this.session.getAttribute(any())).thenReturn(Optional.empty());
@@ -136,9 +135,13 @@ public class SessionAttributeMethodArgumentResolverTests {
assertEquals(Optional.class, mono.block().getClass());
assertFalse(((Optional) mono.block()).isPresent());
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
BindingContext bindingContext = new BindingContext(initializer);
Foo foo = new Foo();
when(this.session.getAttribute("foo")).thenReturn(Optional.of(foo));
mono = this.resolver.resolveArgument(param, new BindingContext(), this.exchange);
mono = this.resolver.resolveArgument(param, bindingContext, this.exchange);
assertNotNull(mono.block());
assertEquals(Optional.class, mono.block().getClass());