Refine validator and MVC validator configuration
Update `ValidationAutoConfiguration` and `WebMvcAutoConfiguration` to ensure as much as possible that only a single Validator bean of each type is registered. Validation auto-configuration now does the following: - If no validator is found: Registers a `LocalValidatorFactoryBean` (providing both Spring and JSR validation) - If the user defines a Spring & JSR validator: Backs off - If the user defines only a JSR validator: Adapts it to a Spring validator (without exposing another JSR implementation) WebMvcAutoConfiguration auto-configuration has been updated to make MVC validation follow common Spring Boot patterns: - If not validator beans are found (due to the user excluding ValidationAutoConfiguration) a new `mvcValidator` bean will be registered. - If a single validator bean is found it will be used for MVC validation. - If multiple validator beans are defined it will either use the one named `mvcValidator` or it will register a new `mvcValidator` bean Any automatically registered `mvcValidator` bean will not implement the JSR validator interface. Finally, it is no longer possible to provide an MVC validator via a `WebMvcConfigurer`. Fixes gh-8495
This commit is contained in:
parent
2a7fd5011d
commit
c9561f031c
|
@ -41,6 +41,7 @@ import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMappingCusto
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
|
||||
|
@ -156,9 +157,9 @@ public class EndpointMvcIntegrationTests {
|
|||
@Documented
|
||||
@Import({ EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
/**
|
||||
* Default validator configuration imported by {@link ValidationAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
class DefaultValidatorConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(type = { "javax.validation.Validator",
|
||||
"org.springframework.validation.Validator" })
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public static LocalValidatorFactoryBean defaultValidator() {
|
||||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
|
||||
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
/**
|
||||
* {@link Validator} implementation that delegates calls to another {@link Validator}.
|
||||
* This {@link Validator} implements Spring's {@link SmartValidator} interface but does
|
||||
* not implement the JSR-303 {@code javax.validator.Validator} interface.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.5.3
|
||||
*/
|
||||
public class DelegatingValidator implements SmartValidator {
|
||||
|
||||
private final Validator delegate;
|
||||
|
||||
/**
|
||||
* Create a new {@link DelegatingValidator} instance.
|
||||
* @param targetValidator the target JSR validator
|
||||
*/
|
||||
public DelegatingValidator(javax.validation.Validator targetValidator) {
|
||||
this.delegate = new SpringValidatorAdapter(targetValidator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link DelegatingValidator} instance.
|
||||
* @param targetValidator the target validator
|
||||
*/
|
||||
public DelegatingValidator(Validator targetValidator) {
|
||||
Assert.notNull(targetValidator, "Target Validator must not be null");
|
||||
this.delegate = targetValidator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return this.delegate.supports(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
this.delegate.validate(target, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors, Object... validationHints) {
|
||||
if (this.delegate instanceof SmartValidator) {
|
||||
((SmartValidator) this.delegate).validate(target, errors, validationHints);
|
||||
}
|
||||
else {
|
||||
this.delegate.validate(target, errors);
|
||||
}
|
||||
}
|
||||
|
||||
protected final Validator getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import javax.validation.Validator;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
|
||||
/**
|
||||
* JSR 303 adapter configration imported by {@link ValidationAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration
|
||||
class Jsr303ValidatorAdapterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnSingleCandidate(Validator.class)
|
||||
@ConditionalOnMissingBean(org.springframework.validation.Validator.class)
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public SmartValidator jsr303ValidatorAdapter(Validator validator) {
|
||||
return new DelegatingValidator(validator);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,18 +19,16 @@ package org.springframework.boot.autoconfigure.validation;
|
|||
import javax.validation.Validator;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
/**
|
||||
|
@ -43,19 +41,12 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
|||
@Configuration
|
||||
@ConditionalOnClass(ExecutableValidator.class)
|
||||
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
|
||||
@Import({ DefaultValidatorConfiguration.class,
|
||||
Jsr303ValidatorAdapterConfiguration.class })
|
||||
public class ValidationAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
@ConditionalOnMissingBean
|
||||
public static Validator jsr303Validator() {
|
||||
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
|
||||
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
|
||||
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(Validator.class)
|
||||
@ConditionalOnMissingBean
|
||||
public static MethodValidationPostProcessor methodValidationPostProcessor(
|
||||
Environment environment, Validator validator) {
|
||||
|
|
|
@ -30,11 +30,21 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
|
@ -43,27 +53,38 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.filter.OrderedHiddenHttpMethodFilter;
|
||||
import org.springframework.boot.web.filter.OrderedHttpPutFormContentFilter;
|
||||
import org.springframework.boot.web.filter.OrderedRequestContextFilter;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Role;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
|
@ -142,6 +163,12 @@ public class WebMvcAutoConfiguration {
|
|||
public static final String SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
|
||||
.getName() + ".SKIP";
|
||||
|
||||
@Bean
|
||||
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
public static MvcValidatorPostProcessor mvcValidatorAliasPostProcessor() {
|
||||
return new MvcValidatorPostProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
|
||||
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
|
||||
|
@ -367,21 +394,22 @@ public class WebMvcAutoConfiguration {
|
|||
* Configuration equivalent to {@code @EnableWebMvc}.
|
||||
*/
|
||||
@Configuration
|
||||
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
|
||||
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
|
||||
implements InitializingBean {
|
||||
|
||||
private final WebMvcProperties mvcProperties;
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
private final ApplicationContext context;
|
||||
|
||||
private final WebMvcRegistrations mvcRegistrations;
|
||||
|
||||
public EnableWebMvcConfiguration(
|
||||
ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
|
||||
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
|
||||
ListableBeanFactory beanFactory) {
|
||||
ApplicationContext context) {
|
||||
this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
|
||||
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
|
||||
this.beanFactory = beanFactory;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -412,12 +440,9 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
@Bean
|
||||
@Override
|
||||
@Conditional(DisableMvcValidatorCondition.class)
|
||||
public Validator mvcValidator() {
|
||||
if (!ClassUtils.isPresent("javax.validation.Validator",
|
||||
getClass().getClassLoader())) {
|
||||
return super.mvcValidator();
|
||||
}
|
||||
return WebMvcValidator.get(getApplicationContext(), getValidator());
|
||||
return this.context.getBean("mvcValidator", Validator.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -432,7 +457,7 @@ public class WebMvcAutoConfiguration {
|
|||
@Override
|
||||
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
|
||||
try {
|
||||
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
|
||||
return this.context.getBean(ConfigurableWebBindingInitializer.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return super.getConfigurableWebBindingInitializer();
|
||||
|
@ -481,6 +506,15 @@ public class WebMvcAutoConfiguration {
|
|||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(getValidator() == null,
|
||||
"Found unexpected validator configuration. A Spring Boot MVC "
|
||||
+ "validator should be registered as bean named "
|
||||
+ "'mvcValidator' and not returned from "
|
||||
+ "WebMvcConfigurer.getValidator()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -606,4 +640,128 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition used to disable the default MVC validator registration. The
|
||||
* {@link MvcValidatorPostProcessor} is used to configure the {@code mvcValidator}
|
||||
* bean.
|
||||
*/
|
||||
static class DisableMvcValidatorCondition implements ConfigurationCondition {
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration.
|
||||
* Applies the following rules:
|
||||
* <ul>
|
||||
* <li>With no validators - Uses standard
|
||||
* {@link WebMvcConfigurationSupport#mvcValidator()} logic.</li>
|
||||
* <li>With a single validator - Uses an alias.</li>
|
||||
* <li>With multiple validators - Registers a mvcValidator bean if not already
|
||||
* defined.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
static class MvcValidatorPostProcessor
|
||||
implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
|
||||
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
|
||||
throws BeansException {
|
||||
if (registry instanceof ListableBeanFactory) {
|
||||
postProcess(registry, (ListableBeanFactory) registry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
}
|
||||
|
||||
private void postProcess(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
|
||||
beanFactory, Validator.class, false, false);
|
||||
if (validatorBeans.length == 0) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
else if (validatorBeans.length == 1) {
|
||||
registry.registerAlias(validatorBeans[0], "mvcValidator");
|
||||
}
|
||||
else {
|
||||
if (!ObjectUtils.containsElement(validatorBeans, "mvcValidator")) {
|
||||
registerMvcValidator(registry, beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerMvcValidator(BeanDefinitionRegistry registry,
|
||||
ListableBeanFactory beanFactory) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setBeanClass(getClass());
|
||||
definition.setFactoryMethodName("mvcValidator");
|
||||
registry.registerBeanDefinition("mvcValidator", definition);
|
||||
}
|
||||
|
||||
static Validator mvcValidator() {
|
||||
Validator validator = new WebMvcConfigurationSupport().mvcValidator();
|
||||
try {
|
||||
if (ClassUtils.forName(JSR303_VALIDATOR_CLASS, null)
|
||||
.isInstance(validator)) {
|
||||
return new DelegatingWebMvcValidator(validator);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DelegatingValidator} for the MVC validator.
|
||||
*/
|
||||
static class DelegatingWebMvcValidator extends DelegatingValidator
|
||||
implements ApplicationContextAware, InitializingBean, DisposableBean {
|
||||
|
||||
public DelegatingWebMvcValidator(Validator targetValidator) {
|
||||
super(targetValidator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (getDelegate() instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) getDelegate())
|
||||
.setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (getDelegate() instanceof InitializingBean) {
|
||||
((InitializingBean) getDelegate()).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (getDelegate() instanceof DisposableBean) {
|
||||
((DisposableBean) getDelegate()).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.validation.MessageInterpolatorFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
|
||||
/**
|
||||
* A {@link SmartValidator} exposed as a bean for WebMvc use. Wraps existing
|
||||
* {@link SpringValidatorAdapter} instances so that only the Spring's {@link Validator}
|
||||
* type is exposed. This prevents such a bean to expose both the Spring and JSR-303
|
||||
* validator contract at the same time.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class WebMvcValidator implements SmartValidator, ApplicationContextAware,
|
||||
InitializingBean, DisposableBean {
|
||||
|
||||
private final SpringValidatorAdapter target;
|
||||
|
||||
private final boolean existingBean;
|
||||
|
||||
WebMvcValidator(SpringValidatorAdapter target, boolean existingBean) {
|
||||
this.target = target;
|
||||
this.existingBean = existingBean;
|
||||
}
|
||||
|
||||
SpringValidatorAdapter getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return this.target.supports(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
this.target.validate(target, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors, Object... validationHints) {
|
||||
this.target.validate(target, errors, validationHints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
if (!this.existingBean && this.target instanceof ApplicationContextAware) {
|
||||
((ApplicationContextAware) this.target)
|
||||
.setApplicationContext(applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (!this.existingBean && this.target instanceof InitializingBean) {
|
||||
((InitializingBean) this.target).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (!this.existingBean && this.target instanceof DisposableBean) {
|
||||
((DisposableBean) this.target).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public static Validator get(ApplicationContext applicationContext,
|
||||
Validator validator) {
|
||||
if (validator != null) {
|
||||
return wrap(validator, false);
|
||||
}
|
||||
return getExistingOrCreate(applicationContext);
|
||||
}
|
||||
|
||||
private static Validator getExistingOrCreate(ApplicationContext applicationContext) {
|
||||
Validator existing = getExisting(applicationContext);
|
||||
if (existing != null) {
|
||||
return wrap(existing, true);
|
||||
}
|
||||
return create();
|
||||
}
|
||||
|
||||
private static Validator getExisting(ApplicationContext applicationContext) {
|
||||
try {
|
||||
javax.validation.Validator validator = applicationContext
|
||||
.getBean(javax.validation.Validator.class);
|
||||
if (validator instanceof Validator) {
|
||||
return (Validator) validator;
|
||||
}
|
||||
return new SpringValidatorAdapter(validator);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Validator create() {
|
||||
OptionalValidatorFactoryBean validator = new OptionalValidatorFactoryBean();
|
||||
validator.setMessageInterpolator(new MessageInterpolatorFactory().getObject());
|
||||
return wrap(validator, false);
|
||||
}
|
||||
|
||||
private static Validator wrap(Validator validator, boolean existingBean) {
|
||||
if (validator instanceof javax.validation.Validator) {
|
||||
if (validator instanceof SpringValidatorAdapter) {
|
||||
return new WebMvcValidator((SpringValidatorAdapter) validator,
|
||||
existingBean);
|
||||
}
|
||||
return new WebMvcValidator(
|
||||
new SpringValidatorAdapter((javax.validation.Validator) validator),
|
||||
existingBean);
|
||||
}
|
||||
return validator;
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ import org.junit.Test;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
|
||||
|
@ -324,9 +325,9 @@ public class SpringBootWebSecurityConfigurationTests {
|
|||
@Documented
|
||||
@Import({ EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.validation;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link DelegatingValidator}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DelegatingValidatorTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Mock
|
||||
private SmartValidator delegate;
|
||||
|
||||
private DelegatingValidator delegating;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
this.delegating = new DelegatingValidator(this.delegate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWhenJsrValidatorIsNullShouldThrowException() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Target Validator must not be null");
|
||||
new DelegatingValidator((javax.validation.Validator) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithJsrValidatorShouldAdapt() throws Exception {
|
||||
javax.validation.Validator delegate = mock(javax.validation.Validator.class);
|
||||
Validator delegating = new DelegatingValidator(delegate);
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
delegating.validate(target, errors);
|
||||
verify(delegate).validate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithSpringValidatorWhenValidatorIsNullShouldThrowException()
|
||||
throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Target Validator must not be null");
|
||||
new DelegatingValidator((Validator) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsShouldDelegateToValidator() throws Exception {
|
||||
this.delegating.supports(Object.class);
|
||||
verify(this.delegate).supports(Object.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateShouldDelegateToValidator() throws Exception {
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
this.delegating.validate(target, errors);
|
||||
verify(this.delegate).validate(target, errors);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithHintsShouldDelegateToValidator() throws Exception {
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
Object[] hints = { "foo", "bar" };
|
||||
this.delegating.validate(target, errors, hints);
|
||||
verify(this.delegate).validate(target, errors, hints);
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateWithHintsWhenDelegateIsNotSmartShouldDelegateToSimpleValidator()
|
||||
throws Exception {
|
||||
Validator delegate = mock(Validator.class);
|
||||
DelegatingValidator delegating = new DelegatingValidator(delegate);
|
||||
Object target = new Object();
|
||||
Errors errors = new BeanPropertyBindingResult(target, "foo");
|
||||
Object[] hints = { "foo", "bar" };
|
||||
delegating.validate(target, errors, hints);
|
||||
verify(delegate).validate(target, errors);
|
||||
}
|
||||
|
||||
}
|
|
@ -32,9 +32,12 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ValidationAutoConfiguration}.
|
||||
|
@ -56,45 +59,94 @@ public class ValidationAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void validationIsEnabled() {
|
||||
load(SampleService.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
SampleService service = this.context.getBean(SampleService.class);
|
||||
service.doSomething("Valid");
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething("KO");
|
||||
public void validationAutoConfigurationShouldConfigureJsrAndSpringValidator()
|
||||
throws Exception {
|
||||
load(Config.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isInstanceOf(LocalValidatorFactoryBean.class);
|
||||
assertThat(jsrValidator).isEqualTo(springValidator);
|
||||
assertThat(jsrValidatorNames).containsExactly("defaultValidator");
|
||||
assertThat(springValidatorNames).containsExactly("defaultValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationUsesCglibProxy() {
|
||||
load(DefaultAnotherSampleService.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
DefaultAnotherSampleService service = this.context
|
||||
.getBean(DefaultAnotherSampleService.class);
|
||||
service.doSomething(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething(2);
|
||||
public void validationAutoConfigurationWhenUserProvidesValidatorShouldBackOff()
|
||||
throws Exception {
|
||||
load(UserDefinedValidatorConfig.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isInstanceOf(OptionalValidatorFactoryBean.class);
|
||||
assertThat(jsrValidator).isEqualTo(springValidator);
|
||||
assertThat(jsrValidatorNames).containsExactly("customValidator");
|
||||
assertThat(springValidatorNames).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCanBeConfiguredToUseJdkProxy() {
|
||||
public void validationAutoConfigurationWhenUserProvidesJsrOnlyShouldAdaptIt()
|
||||
throws Exception {
|
||||
load(UserDefinedJsrValidatorConfig.class);
|
||||
Validator jsrValidator = this.context.getBean(Validator.class);
|
||||
String[] jsrValidatorNames = this.context.getBeanNamesForType(Validator.class);
|
||||
org.springframework.validation.Validator springValidator = this.context
|
||||
.getBean(org.springframework.validation.Validator.class);
|
||||
String[] springValidatorNames = this.context
|
||||
.getBeanNamesForType(org.springframework.validation.Validator.class);
|
||||
assertThat(jsrValidator).isNotEqualTo(springValidator);
|
||||
assertThat(springValidator).isInstanceOf(DelegatingValidator.class);
|
||||
assertThat(jsrValidatorNames).containsExactly("customValidator");
|
||||
assertThat(springValidatorNames).containsExactly("jsr303ValidatorAdapter");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationShouldBeEnabled() {
|
||||
load(ClassWithConstraint.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
ClassWithConstraint service = this.context.getBean(ClassWithConstraint.class);
|
||||
service.call("Valid");
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.call("KO");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationShouldUseCglibProxy() {
|
||||
load(ImplementationOfInterfaceWithConstraint.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
ImplementationOfInterfaceWithConstraint service = this.context
|
||||
.getBean(ImplementationOfInterfaceWithConstraint.class);
|
||||
service.call(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.call(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationAutoConfigurationWhenProxyTargetClassIsFalseShouldUseJdkProxy() {
|
||||
load(AnotherSampleServiceConfiguration.class,
|
||||
"spring.aop.proxy-target-class=false");
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(DefaultAnotherSampleService.class))
|
||||
.isEmpty();
|
||||
AnotherSampleService service = this.context.getBean(AnotherSampleService.class);
|
||||
service.doSomething(42);
|
||||
assertThat(this.context
|
||||
.getBeansOfType(ImplementationOfInterfaceWithConstraint.class)).isEmpty();
|
||||
InterfaceWithConstraint service = this.context
|
||||
.getBean(InterfaceWithConstraint.class);
|
||||
service.call(42);
|
||||
this.thrown.expect(ConstraintViolationException.class);
|
||||
service.doSomething(2);
|
||||
service.call(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userDefinedMethodValidationPostProcessorTakesPrecedence() {
|
||||
load(SampleConfiguration.class);
|
||||
public void validationAutoConfigurationWhenUserDefinesMethodValidationPostProcessorShouldBackOff() {
|
||||
load(UserDefinedMethodValidationConfig.class);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Object userMethodValidationPostProcessor = this.context
|
||||
.getBean("testMethodValidationPostProcessor");
|
||||
.getBean("customMethodValidationPostProcessor");
|
||||
assertThat(this.context.getBean(MethodValidationPostProcessor.class))
|
||||
.isSameAs(userMethodValidationPostProcessor);
|
||||
assertThat(this.context.getBeansOfType(MethodValidationPostProcessor.class))
|
||||
|
@ -115,47 +167,73 @@ public class ValidationAutoConfigurationTests {
|
|||
this.context = ctx;
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class SampleService {
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
public void doSomething(@Size(min = 3, max = 10) String name) {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedValidatorConfig {
|
||||
|
||||
@Bean
|
||||
public OptionalValidatorFactoryBean customValidator() {
|
||||
return new OptionalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface AnotherSampleService {
|
||||
@Configuration
|
||||
static class UserDefinedJsrValidatorConfig {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
void doSomething(@Min(42) Integer counter);
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class DefaultAnotherSampleService implements AnotherSampleService {
|
||||
|
||||
@Override
|
||||
public void doSomething(Integer counter) {
|
||||
@Configuration
|
||||
static class UserDefinedMethodValidationConfig {
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor customMethodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class AnotherSampleServiceConfiguration {
|
||||
|
||||
@Bean
|
||||
public AnotherSampleService anotherSampleService() {
|
||||
return new DefaultAnotherSampleService();
|
||||
public InterfaceWithConstraint implementationOfInterfaceWithConstraint() {
|
||||
return new ImplementationOfInterfaceWithConstraint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SampleConfiguration {
|
||||
@Validated
|
||||
static class ClassWithConstraint {
|
||||
|
||||
public void call(@Size(min = 3, max = 10) String name) {
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor testMethodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface InterfaceWithConstraint {
|
||||
|
||||
void call(@Min(42) Integer counter);
|
||||
}
|
||||
|
||||
@Validated
|
||||
static class ImplementationOfInterfaceWithConstraint
|
||||
implements InterfaceWithConstraint {
|
||||
|
||||
@Override
|
||||
public void call(Integer counter) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.junit.rules.ExpectedException;
|
|||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.util.ApplicationContextTestUtils;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -126,9 +127,9 @@ public class BasicErrorControllerDirectMockMvcTests {
|
|||
@Documented
|
||||
@Import({ EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.junit.runner.RunWith;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -128,9 +129,9 @@ public class BasicErrorControllerMockMvcTests {
|
|||
@Import({ EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat.class,
|
||||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })
|
||||
protected @interface MinimalWebConfiguration {
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.Map;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -37,8 +36,11 @@ import org.junit.Test;
|
|||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.validation.DelegatingValidator;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration.WelcomePageHandlerMapping;
|
||||
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
|
||||
|
@ -59,11 +61,11 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
|||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.validation.beanvalidation.SpringValidatorAdapter;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.filter.HttpPutFormContentFilter;
|
||||
|
@ -655,77 +657,154 @@ public class WebMvcAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void validationNoJsr303ValidatorExposedByDefault() {
|
||||
public void validatorWhenSuppliedByConfigurerShouldThrowException() throws Exception {
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
this.thrown.expectMessage("unexpected validator configuration");
|
||||
load(ValidatorWebMvcConfigurer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenAutoConfiguredShouldUseAlias() throws Exception {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Object defaultValidator = this.context.getBean("defaultValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(defaultValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("defaultValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("defaultValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedence() {
|
||||
load(MvcValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator)
|
||||
.isSameAs(this.context.getBean(MvcValidator.class).validator);
|
||||
public void validatorWhenUserDefinedSpringOnlyShouldUseDefined() throws Exception {
|
||||
load(UserDefinedSpringOnlyValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationCustomConfigurerTakesPrecedenceAndDoNotExposeJsr303() {
|
||||
load(MvcJsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(WebMvcValidator.class);
|
||||
assertThat(((WebMvcValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(MvcJsr303Validator.class).validator);
|
||||
public void validatorWhenUserDefinedJsr303ShouldAdapt() throws Exception {
|
||||
load(UserDefinedJsr303Validator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("jsr303ValidatorAdapter");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303CustomValidatorReusedAsSpringValidator() {
|
||||
load(CustomValidator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(2);
|
||||
Validator validator = this.context.getBean("mvcValidator", Validator.class);
|
||||
assertThat(validator).isInstanceOf(WebMvcValidator.class);
|
||||
assertThat(((WebMvcValidator) validator).getTarget())
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedSingleJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedSingleJsr303AndSpringValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isSameAs(customValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customValidator);
|
||||
assertThat(this.context.getBean(Validator.class)).isEqualTo(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validationJsr303ValidatorExposedAsSpringValidator() {
|
||||
load(Jsr303Validator.class);
|
||||
assertThat(this.context.getBeansOfType(ValidatorFactory.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(javax.validation.Validator.class))
|
||||
.hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Validator.class)).hasSize(1);
|
||||
Validator validator = this.context.getBean(Validator.class);
|
||||
assertThat(validator).isInstanceOf(WebMvcValidator.class);
|
||||
SpringValidatorAdapter target = ((WebMvcValidator) validator)
|
||||
.getTarget();
|
||||
assertThat(new DirectFieldAccessor(target).getPropertyValue("targetValidator"))
|
||||
.isSameAs(this.context.getBean(javax.validation.Validator.class));
|
||||
public void validatorWhenUserDefinedJsr303AndSpringShouldUseDefined()
|
||||
throws Exception {
|
||||
load(UserDefinedJsr303AndSpringValidator.class);
|
||||
Object customJsrValidator = this.context.getBean("customJsrValidator");
|
||||
Object customSpringValidator = this.context.getBean("customSpringValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(customJsrValidator).isNotSameAs(customSpringValidator);
|
||||
assertThat(mvcValidator).isSameAs(customSpringValidator);
|
||||
assertThat(this.context.getBean(javax.validation.Validator.class))
|
||||
.isEqualTo(customJsrValidator);
|
||||
assertThat(this.context.getBean(Validator.class))
|
||||
.isEqualTo(customSpringValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customSpringValidator");
|
||||
assertThat(jsrValidatorBeans).containsExactly("customJsrValidator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenExcludingValidatorAutoConfigurationShouldUseMvc()
|
||||
throws Exception {
|
||||
load(null, new Class[] { ValidationAutoConfiguration.class });
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isInstanceOf(DelegatingValidator.class);
|
||||
assertThat(springValidatorBeans).containsExactly("mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndNoMvcValidatorShouldAddMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndNoMvcValidator.class);
|
||||
Object customValidator1 = this.context.getBean("customValidator1");
|
||||
Object customValidator2 = this.context.getBean("customValidator2");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator1)
|
||||
.isNotSameAs(customValidator2);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator1",
|
||||
"customValidator2", "mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validatorWhenMultipleValidatorsAndMvcValidatorShouldUseMvc()
|
||||
throws Exception {
|
||||
load(MultipleValidatorsAndMvcValidator.class);
|
||||
Object customValidator = this.context.getBean("customValidator");
|
||||
Object mvcValidator = this.context.getBean("mvcValidator");
|
||||
String[] jsrValidatorBeans = this.context
|
||||
.getBeanNamesForType(javax.validation.Validator.class);
|
||||
String[] springValidatorBeans = this.context.getBeanNamesForType(Validator.class);
|
||||
assertThat(mvcValidator).isNotSameAs(customValidator);
|
||||
assertThat(springValidatorBeans).containsExactly("customValidator",
|
||||
"mvcValidator");
|
||||
assertThat(jsrValidatorBeans).isEmpty();
|
||||
}
|
||||
|
||||
private void load(Class<?> config, String... environment) {
|
||||
load(config, null, environment);
|
||||
}
|
||||
|
||||
private void load(Class<?> config, Class<?>[] exclude, String... environment) {
|
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context, environment);
|
||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||
if (config != null) {
|
||||
configClasses.add(config);
|
||||
}
|
||||
configClasses.addAll(Arrays.asList(Config.class, WebMvcAutoConfiguration.class,
|
||||
configClasses.addAll(Arrays.asList(Config.class,
|
||||
ValidationAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class));
|
||||
if (!ObjectUtils.isEmpty(exclude)) {
|
||||
configClasses.removeAll(Arrays.asList(exclude));
|
||||
}
|
||||
this.context.register(configClasses.toArray(new Class<?>[configClasses.size()]));
|
||||
this.context.refresh();
|
||||
}
|
||||
|
@ -895,47 +974,88 @@ public class WebMvcAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MvcValidator extends WebMvcConfigurerAdapter {
|
||||
|
||||
private final Validator validator = mock(Validator.class);
|
||||
protected static class ValidatorWebMvcConfigurer extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
public Validator getValidator() {
|
||||
return this.validator;
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MvcJsr303Validator extends WebMvcConfigurerAdapter {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
|
||||
|
||||
@Override
|
||||
public Validator getValidator() {
|
||||
return this.validator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class Jsr303Validator {
|
||||
static class UserDefinedSpringOnlyValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator jsr303Validator() {
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303Validator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomValidator {
|
||||
static class UserDefinedSingleJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
public LocalValidatorFactoryBean customValidator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class UserDefinedJsr303AndSpringValidator {
|
||||
|
||||
@Bean
|
||||
public javax.validation.Validator customJsrValidator() {
|
||||
return mock(javax.validation.Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customSpringValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndNoMvcValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator1() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator customValidator2() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleValidatorsAndMvcValidator {
|
||||
|
||||
@Bean
|
||||
public Validator customValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Validator mvcValidator() {
|
||||
return mock(Validator.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.MapBindingResult;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link WebMvcValidator}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class WebMvcValidatorTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapLocalValidatorFactoryBean() {
|
||||
WebMvcValidator wrapper = load(
|
||||
LocalValidatorFactoryBeanConfig.class);
|
||||
assertThat(wrapper.supports(SampleData.class)).isTrue();
|
||||
MapBindingResult errors = new MapBindingResult(new HashMap<String, Object>(),
|
||||
"test");
|
||||
wrapper.validate(new SampleData(40), errors);
|
||||
assertThat(errors.getErrorCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapperInvokesCallbackOnNonManagedBean() {
|
||||
load(NonManagedBeanConfig.class);
|
||||
LocalValidatorFactoryBean validator = this.context
|
||||
.getBean(NonManagedBeanConfig.class).validator;
|
||||
verify(validator, times(1)).setApplicationContext(any(ApplicationContext.class));
|
||||
verify(validator, times(1)).afterPropertiesSet();
|
||||
verify(validator, times(0)).destroy();
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
verify(validator, times(1)).destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapperDoesNotInvokeCallbackOnManagedBean() {
|
||||
load(ManagedBeanConfig.class);
|
||||
LocalValidatorFactoryBean validator = this.context
|
||||
.getBean(ManagedBeanConfig.class).validator;
|
||||
verify(validator, times(0)).setApplicationContext(any(ApplicationContext.class));
|
||||
verify(validator, times(0)).afterPropertiesSet();
|
||||
verify(validator, times(0)).destroy();
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
verify(validator, times(0)).destroy();
|
||||
}
|
||||
|
||||
private WebMvcValidator load(Class<?> config) {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(config);
|
||||
ctx.refresh();
|
||||
this.context = ctx;
|
||||
return this.context.getBean(WebMvcValidator.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class LocalValidatorFactoryBeanConfig {
|
||||
|
||||
@Bean
|
||||
public LocalValidatorFactoryBean validator() {
|
||||
return new LocalValidatorFactoryBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcValidator wrapper() {
|
||||
return new WebMvcValidator(validator(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class NonManagedBeanConfig {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = mock(
|
||||
LocalValidatorFactoryBean.class);
|
||||
|
||||
@Bean
|
||||
public WebMvcValidator wrapper() {
|
||||
return new WebMvcValidator(this.validator, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ManagedBeanConfig {
|
||||
|
||||
private final LocalValidatorFactoryBean validator = mock(
|
||||
LocalValidatorFactoryBean.class);
|
||||
|
||||
@Bean
|
||||
public WebMvcValidator wrapper() {
|
||||
return new WebMvcValidator(this.validator, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class SampleData {
|
||||
|
||||
@Min(42)
|
||||
private int counter;
|
||||
|
||||
SampleData(int counter) {
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue