diff --git a/spring-web-reactive/build.gradle b/spring-web-reactive/build.gradle index ab52dcf29a..15b2b0ede0 100644 --- a/spring-web-reactive/build.gradle +++ b/spring-web-reactive/build.gradle @@ -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" diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java index ee727228a6..e30c1e4fc3 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java @@ -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. + *
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) {
+ }
+ }
+
}
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
index 2cbc579437..dba37ad1f8 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
@@ -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