Add global Validator bean to WebReactiveConfiguration

master
Rossen Stoyanchev 8 years ago
parent 2f8baac4e0
commit 551b7cd60e
  1. 1
      spring-web-reactive/build.gradle
  2. 58
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java
  3. 23
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
  4. 8
      spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java

@ -111,6 +111,7 @@ dependencies {
optional "org.eclipse.jetty:jetty-servlet:${jettyVersion}"
optional("org.freemarker:freemarker:2.3.23")
optional("com.fasterxml:aalto-xml:1.0.0")
optional("javax.validation:validation-api:1.0.0.GA")
provided "javax.servlet:javax.servlet-api:3.1.0"

@ -22,6 +22,8 @@ import java.util.Map;
import reactor.core.converter.DependencyUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
@ -48,6 +50,8 @@ import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
import org.springframework.http.converter.reactive.HttpMessageConverter;
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.SimpleHandlerAdapter;
@ -185,6 +189,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
adapter.setMessageConverters(getMessageConverters());
adapter.setConversionService(mvcConversionService());
adapter.setValidator(mvcValidator());
return adapter;
}
@ -284,6 +289,46 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
}
}
/**
* Return a global {@link Validator} instance for example for validating
* {@code @RequestBody} method arguments.
* <p>Delegates to {@link #getValidator()} first. If that returns {@code null}
* checks the classpath for the presence of a JSR-303 implementations
* before creating a {@code OptionalValidatorFactoryBean}. If a JSR-303
* implementation is not available, a "no-op" {@link Validator} is returned.
*/
@Bean
public Validator mvcValidator() {
Validator validator = getValidator();
if (validator == null) {
if (ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
Class<?> clazz;
try {
String name = "org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean";
clazz = ClassUtils.forName(name, classLoader);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException("Could not find default validator class", ex);
}
catch (LinkageError ex) {
throw new BeanInitializationException("Could not load default validator class", ex);
}
validator = (Validator) BeanUtils.instantiate(clazz);
}
else {
validator = new NoOpValidator();
}
}
return validator;
}
/**
* Override this method to provide a custom {@link Validator}.
*/
protected Validator getValidator() {
return null;
}
@Bean
public SimpleHandlerAdapter simpleHandlerAdapter() {
return new SimpleHandlerAdapter();
@ -317,4 +362,17 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
protected void configureViewResolvers(ViewResolverRegistry registry) {
}
private static final class NoOpValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return false;
}
@Override
public void validate(Object target, Errors errors) {
}
}
}

@ -39,7 +39,7 @@ import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
import org.springframework.http.converter.reactive.HttpMessageConverter;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.Validator;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
import org.springframework.web.reactive.HandlerAdapter;
@ -67,6 +67,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
private ConversionService conversionService = new DefaultFormattingConversionService();
private Validator validator;
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = new ConcurrentHashMap<>(64);
@ -141,6 +143,23 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
return this.conversionService;
}
/**
* Configure a Validator for validation of controller method arguments such
* as {@code @RequestBody}.
*
* TODO: this may be replaced by DataBinder
*/
public void setValidator(Validator validator) {
this.validator = validator;
}
/**
* Return the configured Validator.
*/
public Validator getValidator() {
return this.validator;
}
/**
* A {@link ConfigurableBeanFactory} is expected for resolving expressions
* in method argument default values.
@ -173,7 +192,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new RequestBodyArgumentResolver(getMessageConverters(), cs));
resolvers.add(new RequestBodyArgumentResolver(getMessageConverters(), cs, getValidator()));
resolvers.add(new RequestHeaderMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new CookieValueMethodArgumentResolver(cs, getBeanFactory()));

@ -20,7 +20,6 @@ import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Before;
@ -50,6 +49,8 @@ import org.springframework.http.server.reactive.MockServerHttpRequest;
import org.springframework.http.server.reactive.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.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
@ -148,6 +149,11 @@ public class WebReactiveConfigurationTests {
name = "mvcConversionService";
ConversionService service = context.getBean(name, ConversionService.class);
assertSame(service, adapter.getConversionService());
name = "mvcValidator";
Validator validator = context.getBean(name, Validator.class);
assertSame(validator, adapter.getValidator());
assertEquals(OptionalValidatorFactoryBean.class, validator.getClass());
}
@Test

Loading…
Cancel
Save