Commit 7c4a1a22 authored by Stephane Nicoll's avatar Stephane Nicoll

Merge branch '1.5.x'

parents b8fe06c1 1de2316a
/*
* 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;
}
}
/*
* 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);
}
}
/**
* Return the delegate validator.
* @return the delegate validator
*/
protected final Validator getDelegate() {
return this.delegate;
}
}
/*
* 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);
}
}
/*
* 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.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
/**
* Enable the {@code Primary} flag on the auto-configured validator if necessary.
* <p>
* As {@link LocalValidatorFactoryBean} exposes 3 validator related contracts and we're
* only checking for the absence {@link javax.validation.Validator}, we should flag the
* auto-configured validator as primary only if no Spring's {@link Validator} is flagged
* as primary.
*
* @author Stephane Nicoll
*/
class PrimaryDefaultValidatorPostProcessor
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
/**
* The bean name of the auto-configured Validator.
*/
private static final String VALIDATOR_BEAN_NAME = "defaultValidator";
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
if (!registry.containsBeanDefinition(VALIDATOR_BEAN_NAME)) {
return;
}
BeanDefinition def = registry.getBeanDefinition(VALIDATOR_BEAN_NAME);
if (def != null
&& this.beanFactory.isTypeMatch(VALIDATOR_BEAN_NAME, LocalValidatorFactoryBean.class)
&& def.getRole() == BeanDefinition.ROLE_INFRASTRUCTURE) {
def.setPrimary(!hasPrimarySpringValidator(registry));
}
}
private boolean hasPrimarySpringValidator(BeanDefinitionRegistry registry) {
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Validator.class, false, false);
for (String validatorBean : validatorBeans) {
BeanDefinition def = registry.getBeanDefinition(validatorBean);
if (def != null && def.isPrimary()) {
return true;
}
}
return false;
}
}
...@@ -19,15 +19,18 @@ package org.springframework.boot.autoconfigure.validation; ...@@ -19,15 +19,18 @@ package org.springframework.boot.autoconfigure.validation;
import javax.validation.Validator; import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator; import javax.validation.executable.ExecutableValidator;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnResource; import org.springframework.boot.autoconfigure.condition.ConditionalOnResource;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Role;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
/** /**
...@@ -41,12 +44,20 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess ...@@ -41,12 +44,20 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
@Configuration @Configuration
@ConditionalOnClass(ExecutableValidator.class) @ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider") @ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import({ DefaultValidatorConfiguration.class, @Import(PrimaryDefaultValidatorPostProcessor.class)
Jsr303ValidatorAdapterConfiguration.class })
public class ValidationAutoConfiguration { public class ValidationAutoConfiguration {
@Bean @Bean
@ConditionalOnBean(Validator.class) @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
@Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor( public static MethodValidationPostProcessor methodValidationPostProcessor(
Environment environment, Validator validator) { Environment environment, Validator validator) {
......
/*
* 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.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;
/**
* {@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 Stephane Nicoll
* @author Phillip Webb
* @since 2.0.0
*/
public class ValidatorAdapter implements SmartValidator, ApplicationContextAware,
InitializingBean, DisposableBean {
private final SmartValidator target;
private final boolean existingBean;
ValidatorAdapter(SmartValidator target, boolean existingBean) {
this.target = target;
this.existingBean = existingBean;
}
public final Validator 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();
}
}
/**
* Return a {@link Validator} that only implements the {@link Validator} interface,
* wrapping it if necessary.
* <p>If the specified {@link Validator} is not {@code null}, it is wrapped. If not,
* a {@link javax.validation.Validator} is retrieved from the context and wrapped.
* Otherwise, a new default validator is created.
* @param applicationContext the application context
* @param validator an existing validator to use or {@code null}
* @return the validator to use
*/
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 ValidatorAdapter((SpringValidatorAdapter) validator,
existingBean);
}
return new ValidatorAdapter(
new SpringValidatorAdapter((javax.validation.Validator) validator),
existingBean);
}
return validator;
}
}
...@@ -23,48 +23,30 @@ import java.util.concurrent.TimeUnit; ...@@ -23,48 +23,30 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
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.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.validation.DelegatingValidator; import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain; import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean; 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.Configuration;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.format.Formatter; import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry; import org.springframework.format.FormatterRegistry;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration; import org.springframework.web.reactive.config.DelegatingWebFluxConfiguration;
import org.springframework.web.reactive.config.EnableWebFlux; import org.springframework.web.reactive.config.EnableWebFlux;
...@@ -103,7 +85,7 @@ public class WebFluxAutoConfiguration { ...@@ -103,7 +85,7 @@ public class WebFluxAutoConfiguration {
@Configuration @Configuration
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class }) @EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
@Import({ EnableWebFluxConfiguration.class, WebFluxValidatorRegistrar.class }) @Import({ EnableWebFluxConfiguration.class })
public static class WebFluxConfig implements WebFluxConfigurer { public static class WebFluxConfig implements WebFluxConfigurer {
private static final Log logger = LogFactory.getLog(WebFluxConfig.class); private static final Log logger = LogFactory.getLog(WebFluxConfig.class);
...@@ -209,29 +191,17 @@ public class WebFluxAutoConfiguration { ...@@ -209,29 +191,17 @@ public class WebFluxAutoConfiguration {
* Configuration equivalent to {@code @EnableWebFlux}. * Configuration equivalent to {@code @EnableWebFlux}.
*/ */
@Configuration @Configuration
public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration public static class EnableWebFluxConfiguration
implements InitializingBean { extends DelegatingWebFluxConfiguration {
private final ApplicationContext context;
public EnableWebFluxConfiguration(ApplicationContext context) {
this.context = context;
}
@Bean
@Override @Override
@Conditional(DisableWebFluxValidatorCondition.class) @Bean
public Validator webFluxValidator() { public Validator webFluxValidator() {
return this.context.getBean("webFluxValidator", Validator.class); if (!ClassUtils.isPresent("javax.validation.Validator",
} getClass().getClassLoader())) {
return super.webFluxValidator();
@Override }
public void afterPropertiesSet() throws Exception { return ValidatorAdapter.get(getApplicationContext(), getValidator());
Assert.state(getValidator() == null,
"Found unexpected validator configuration. A Spring Boot WebFlux "
+ "validator should be registered as bean named "
+ "'webFluxValidator' and not returned from "
+ "WebFluxConfigurer.getValidator()");
} }
} }
...@@ -297,130 +267,4 @@ public class WebFluxAutoConfiguration { ...@@ -297,130 +267,4 @@ public class WebFluxAutoConfiguration {
} }
/**
* Condition used to disable the default WebFlux validator registration. The
* {@link WebFluxValidatorRegistrar} is used to register the {@code webFluxValidator}
* bean.
*/
static class DisableWebFluxValidatorCondition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
/**
* {@link ImportBeanDefinitionRegistrar} to deal with the WebFlux validator bean
* registration. Applies the following rules:
* <ul>
* <li>With no validators - Uses standard
* {@link WebFluxConfigurationSupport#webFluxValidator()} logic.</li>
* <li>With a single validator - Uses an alias.</li>
* <li>With multiple validators - Registers a webFluxValidator bean if not already
* defined.</li>
* </ul>
*/
static class WebFluxValidatorRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory instanceof ListableBeanFactory) {
registerOrAliasWebFluxValidator(registry,
(ListableBeanFactory) this.beanFactory);
}
}
private void registerOrAliasWebFluxValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) {
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
beanFactory, Validator.class, false, false);
if (validatorBeans.length == 0) {
registerNewWebFluxValidator(registry, beanFactory);
}
else if (validatorBeans.length == 1) {
registry.registerAlias(validatorBeans[0], "webFluxValidator");
}
else {
if (!ObjectUtils.containsElement(validatorBeans, "webFluxValidator")) {
registerNewWebFluxValidator(registry, beanFactory);
}
}
}
private void registerNewWebFluxValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) {
RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(getClass());
definition.setFactoryMethodName("webFluxValidator");
registry.registerBeanDefinition("webFluxValidator", definition);
}
static Validator webFluxValidator() {
Validator validator = new WebFluxConfigurationSupport().webFluxValidator();
try {
if (ClassUtils.forName(JSR303_VALIDATOR_CLASS, null)
.isInstance(validator)) {
return new DelegatingWebFluxValidator(validator);
}
}
catch (Exception ex) {
}
return validator;
}
}
/**
* {@link DelegatingValidator} for the WebFlux validator.
*/
static class DelegatingWebFluxValidator extends DelegatingValidator
implements ApplicationContextAware, InitializingBean, DisposableBean {
DelegatingWebFluxValidator(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();
}
}
}
} }
...@@ -32,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -32,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
...@@ -323,9 +322,9 @@ public class SpringBootWebSecurityConfigurationTests { ...@@ -323,9 +322,9 @@ public class SpringBootWebSecurityConfigurationTests {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import({ ServletWebServerFactoryAutoConfiguration.class, @Import({ ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration { protected @interface MinimalWebConfiguration {
} }
......
/*
* 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);
}
}
/*
* 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 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 ValidatorAdapter}.
*
* @author Stephane Nicoll
*/
public class ValidatorAdapterTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void wrapLocalValidatorFactoryBean() {
ValidatorAdapter 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 ValidatorAdapter load(Class<?> config) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(config);
ctx.refresh();
this.context = ctx;
return this.context.getBean(ValidatorAdapter.class);
}
@Configuration
static class LocalValidatorFactoryBeanConfig {
@Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
@Bean
public ValidatorAdapter wrapper() {
return new ValidatorAdapter(validator(), true);
}
}
@Configuration
static class NonManagedBeanConfig {
private final LocalValidatorFactoryBean validator = mock(
LocalValidatorFactoryBean.class);
@Bean
public ValidatorAdapter wrapper() {
return new ValidatorAdapter(this.validator, false);
}
}
@Configuration
static class ManagedBeanConfig {
private final LocalValidatorFactoryBean validator = mock(
LocalValidatorFactoryBean.class);
@Bean
public ValidatorAdapter wrapper() {
return new ValidatorAdapter(this.validator, true);
}
}
static class SampleData {
@Min(42)
private int counter;
SampleData(int counter) {
this.counter = counter;
}
}
}
...@@ -36,7 +36,6 @@ import org.junit.rules.ExpectedException; ...@@ -36,7 +36,6 @@ import org.junit.rules.ExpectedException;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
...@@ -130,9 +129,9 @@ public class BasicErrorControllerDirectMockMvcTests { ...@@ -130,9 +129,9 @@ public class BasicErrorControllerDirectMockMvcTests {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import({ ServletWebServerFactoryAutoConfiguration.class, @Import({ ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) PropertyPlaceholderAutoConfiguration.class })
protected @interface MinimalWebConfiguration { protected @interface MinimalWebConfiguration {
} }
......
...@@ -36,7 +36,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -36,7 +36,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
...@@ -132,9 +131,9 @@ public class BasicErrorControllerMockMvcTests { ...@@ -132,9 +131,9 @@ public class BasicErrorControllerMockMvcTests {
@Documented @Documented
@Import({ ServletWebServerFactoryAutoConfiguration.EmbeddedTomcat.class, @Import({ ServletWebServerFactoryAutoConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryAutoConfiguration.class, ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class, DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class }) PropertyPlaceholderAutoConfiguration.class })
private @interface MinimalWebConfiguration { private @interface MinimalWebConfiguration {
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment