Merge branch '1.5.x'

pull/7354/merge
Phillip Webb 8 years ago
commit 99a3ec8b74

@ -29,7 +29,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@ -295,12 +294,13 @@ public abstract class AbstractEndpointHandlerMapping<E extends MvcEndpoint>
private static final class SkipPathExtensionContentNegotiation private static final class SkipPathExtensionContentNegotiation
extends HandlerInterceptorAdapter { extends HandlerInterceptorAdapter {
private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
.getName() + ".SKIP";
@Override @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception { Object handler) throws Exception {
request.setAttribute( request.setAttribute(SKIP_ATTRIBUTE, Boolean.TRUE);
WebMvcAutoConfiguration.SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE,
Boolean.TRUE);
return true; return true;
} }

@ -24,17 +24,15 @@ 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.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; 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.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.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition; 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;
@ -54,13 +52,13 @@ 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.ConfigurationCondition;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Role; 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.annotation.Order;
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.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;
@ -92,6 +90,7 @@ import org.springframework.web.reactive.result.view.ViewResolver;
* @author Rob Winch * @author Rob Winch
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Andy Wilkinson * @author Andy Wilkinson
* @author Phillip Webb
* @since 2.0.0 * @since 2.0.0
*/ */
@Configuration @Configuration
@ -102,15 +101,9 @@ import org.springframework.web.reactive.result.view.ViewResolver;
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAnnotationAutoConfiguration { public class WebFluxAnnotationAutoConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static WebFluxValidatorPostProcessor mvcValidatorAliasPostProcessor() {
return new WebFluxValidatorPostProcessor();
}
@Configuration @Configuration
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class }) @EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
@Import(EnableWebFluxConfiguration.class) @Import({ EnableWebFluxConfiguration.class, WebFluxValidatorRegistrar.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);
@ -306,8 +299,8 @@ public class WebFluxAnnotationAutoConfiguration {
/** /**
* Condition used to disable the default WebFlux validator registration. The * Condition used to disable the default WebFlux validator registration. The
* {@link WebFluxValidatorPostProcessor} is used to configure the * {@link WebFluxValidatorRegistrar} is used to register the {@code webFluxValidator}
* {@code webFluxValidator} bean. * bean.
*/ */
static class DisableWebFluxValidatorCondition implements ConfigurationCondition { static class DisableWebFluxValidatorCondition implements ConfigurationCondition {
@ -324,53 +317,55 @@ public class WebFluxAnnotationAutoConfiguration {
} }
/** /**
* {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration. * {@link ImportBeanDefinitionRegistrar} to deal with the WebFlux validator bean
* Applies the following rules: * registration. Applies the following rules:
* <ul> * <ul>
* <li>With no validators - Uses standard * <li>With no validators - Uses standard
* {@link WebFluxConfigurationSupport#webFluxValidator()} logic.</li> * {@link WebFluxConfigurationSupport#webFluxValidator()} logic.</li>
* <li>With a single validator - Uses an alias.</li> * <li>With a single validator - Uses an alias.</li>
* <li>With multiple validators - Registers a mvcValidator bean if not already * <li>With multiple validators - Registers a webFluxValidator bean if not already
* defined.</li> * defined.</li>
* </ul> * </ul>
*/ */
@Order(Ordered.LOWEST_PRECEDENCE) static class WebFluxValidatorRegistrar
static class WebFluxValidatorPostProcessor implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
implements BeanDefinitionRegistryPostProcessor {
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator"; private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
private BeanFactory beanFactory;
@Override @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
throws BeansException { this.beanFactory = beanFactory;
if (registry instanceof ListableBeanFactory) {
postProcess(registry, (ListableBeanFactory) registry);
}
} }
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
throws BeansException { BeanDefinitionRegistry registry) {
if (this.beanFactory instanceof ListableBeanFactory) {
registerOrAliasWebFluxValidator(registry,
(ListableBeanFactory) this.beanFactory);
}
} }
private void postProcess(BeanDefinitionRegistry registry, private void registerOrAliasWebFluxValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) { ListableBeanFactory beanFactory) {
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
beanFactory, Validator.class, false, false); beanFactory, Validator.class, false, false);
if (validatorBeans.length == 0) { if (validatorBeans.length == 0) {
registerMvcValidator(registry, beanFactory); registerNewWebFluxValidator(registry, beanFactory);
} }
else if (validatorBeans.length == 1) { else if (validatorBeans.length == 1) {
registry.registerAlias(validatorBeans[0], "webFluxValidator"); registry.registerAlias(validatorBeans[0], "webFluxValidator");
} }
else { else {
if (!ObjectUtils.containsElement(validatorBeans, "webFluxValidator")) { if (!ObjectUtils.containsElement(validatorBeans, "webFluxValidator")) {
registerMvcValidator(registry, beanFactory); registerNewWebFluxValidator(registry, beanFactory);
} }
} }
} }
private void registerMvcValidator(BeanDefinitionRegistry registry, private void registerNewWebFluxValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) { ListableBeanFactory beanFactory) {
RootBeanDefinition definition = new RootBeanDefinition(); RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(getClass()); definition.setBeanClass(getClass());

@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -39,11 +40,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
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.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.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition; 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;
@ -72,14 +69,14 @@ 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.ConfigurationCondition;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Role;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
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.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotatedTypeMetadata; 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.format.datetime.DateFormatter; import org.springframework.format.datetime.DateFormatter;
@ -160,19 +157,6 @@ public class WebMvcAutoConfiguration {
public static final String DEFAULT_SUFFIX = ""; public static final String DEFAULT_SUFFIX = "";
/**
* Attribute that can be added to the web request when the
* {@link PathExtensionContentNegotiationStrategy} should be be skipped.
*/
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 @Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class) @ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() { public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
@ -189,7 +173,7 @@ public class WebMvcAutoConfiguration {
// Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not // Defined as a nested config to ensure WebMvcConfigurerAdapter is not read when not
// on the classpath // on the classpath
@Configuration @Configuration
@Import(EnableWebMvcConfiguration.class) @Import({ EnableWebMvcConfiguration.class, MvcValidatorRegistrar.class })
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter { public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
@ -623,6 +607,9 @@ public class WebMvcAutoConfiguration {
static class OptionalPathExtensionContentNegotiationStrategy static class OptionalPathExtensionContentNegotiationStrategy
implements ContentNegotiationStrategy { implements ContentNegotiationStrategy {
private static final String SKIP_ATTRIBUTE = PathExtensionContentNegotiationStrategy.class
.getName() + ".SKIP";
private final ContentNegotiationStrategy delegate; private final ContentNegotiationStrategy delegate;
OptionalPathExtensionContentNegotiationStrategy( OptionalPathExtensionContentNegotiationStrategy(
@ -633,8 +620,7 @@ public class WebMvcAutoConfiguration {
@Override @Override
public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
throws HttpMediaTypeNotAcceptableException { throws HttpMediaTypeNotAcceptableException {
Object skip = webRequest.getAttribute( Object skip = webRequest.getAttribute(SKIP_ATTRIBUTE,
SKIP_PATH_EXTENSION_CONTENT_NEGOTIATION_ATTRIBUTE,
RequestAttributes.SCOPE_REQUEST); RequestAttributes.SCOPE_REQUEST);
if (skip != null && Boolean.parseBoolean(skip.toString())) { if (skip != null && Boolean.parseBoolean(skip.toString())) {
return Collections.emptyList(); return Collections.emptyList();
@ -646,7 +632,7 @@ public class WebMvcAutoConfiguration {
/** /**
* Condition used to disable the default MVC validator registration. The * Condition used to disable the default MVC validator registration. The
* {@link MvcValidatorPostProcessor} is used to configure the {@code mvcValidator} * {@link MvcValidatorRegistrar} is actually used to register the {@code mvcValidator}
* bean. * bean.
*/ */
static class DisableMvcValidatorCondition implements ConfigurationCondition { static class DisableMvcValidatorCondition implements ConfigurationCondition {
@ -664,8 +650,8 @@ public class WebMvcAutoConfiguration {
} }
/** /**
* {@link BeanFactoryPostProcessor} to deal with the MVC validator bean registration. * {@link ImportBeanDefinitionRegistrar} to deal with the MVC validator bean
* Applies the following rules: * registration. Applies the following rules:
* <ul> * <ul>
* <li>With no validators - Uses standard * <li>With no validators - Uses standard
* {@link WebMvcConfigurationSupport#mvcValidator()} logic.</li> * {@link WebMvcConfigurationSupport#mvcValidator()} logic.</li>
@ -674,43 +660,45 @@ public class WebMvcAutoConfiguration {
* defined.</li> * defined.</li>
* </ul> * </ul>
*/ */
@Order(Ordered.LOWEST_PRECEDENCE) static class MvcValidatorRegistrar
static class MvcValidatorPostProcessor implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
implements BeanDefinitionRegistryPostProcessor {
private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator"; private static final String JSR303_VALIDATOR_CLASS = "javax.validation.Validator";
private BeanFactory beanFactory;
@Override @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
throws BeansException { this.beanFactory = beanFactory;
if (registry instanceof ListableBeanFactory) {
postProcess(registry, (ListableBeanFactory) registry);
}
} }
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
throws BeansException { BeanDefinitionRegistry registry) {
if (this.beanFactory instanceof ListableBeanFactory) {
registerOrAliasMvcValidator(registry,
(ListableBeanFactory) this.beanFactory);
}
} }
private void postProcess(BeanDefinitionRegistry registry, private void registerOrAliasMvcValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) { ListableBeanFactory beanFactory) {
String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( String[] validatorBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
beanFactory, Validator.class, false, false); beanFactory, Validator.class, false, false);
if (validatorBeans.length == 0) { if (validatorBeans.length == 0) {
registerMvcValidator(registry, beanFactory); registerNewMvcValidator(registry, beanFactory);
} }
else if (validatorBeans.length == 1) { else if (validatorBeans.length == 1) {
registry.registerAlias(validatorBeans[0], "mvcValidator"); registry.registerAlias(validatorBeans[0], "mvcValidator");
} }
else { else {
if (!ObjectUtils.containsElement(validatorBeans, "mvcValidator")) { if (!ObjectUtils.containsElement(validatorBeans, "mvcValidator")) {
registerMvcValidator(registry, beanFactory); registerNewMvcValidator(registry, beanFactory);
} }
} }
} }
private void registerMvcValidator(BeanDefinitionRegistry registry, private void registerNewMvcValidator(BeanDefinitionRegistry registry,
ListableBeanFactory beanFactory) { ListableBeanFactory beanFactory) {
RootBeanDefinition definition = new RootBeanDefinition(); RootBeanDefinition definition = new RootBeanDefinition();
definition.setBeanClass(getClass()); definition.setBeanClass(getClass());

@ -258,7 +258,7 @@ public class WebFluxAnnotationAutoConfigurationTests {
} }
@Test @Test
public void validatorWhenExcludingValidatorAutoConfigurationShouldUseMvc() public void validatorWhenExcludingValidatorAutoConfigurationShouldUseWebFlux()
throws Exception { throws Exception {
load(null, new Class[] { ValidationAutoConfiguration.class }); load(null, new Class[] { ValidationAutoConfiguration.class });
Object webFluxValidator = this.context.getBean("webFluxValidator"); Object webFluxValidator = this.context.getBean("webFluxValidator");
@ -271,7 +271,7 @@ public class WebFluxAnnotationAutoConfigurationTests {
} }
@Test @Test
public void validatorWhenMultipleValidatorsAndNoWebFluxValidatorShouldAddMvc() public void validatorWhenMultipleValidatorsAndNoWebFluxValidatorShouldAddWebFlux()
throws Exception { throws Exception {
load(MultipleValidatorsAndNoWebFluxValidator.class); load(MultipleValidatorsAndNoWebFluxValidator.class);
Object customValidator1 = this.context.getBean("customValidator1"); Object customValidator1 = this.context.getBean("customValidator1");
@ -288,7 +288,7 @@ public class WebFluxAnnotationAutoConfigurationTests {
} }
@Test @Test
public void validatorWhenMultipleValidatorsAndWebFluxValidatorShouldUseMvc() public void validatorWhenMultipleValidatorsAndWebFluxValidatorShouldUseWebFlux()
throws Exception { throws Exception {
load(MultipleValidatorsAndWebFluxValidator.class); load(MultipleValidatorsAndWebFluxValidator.class);
Object customValidator = this.context.getBean("customValidator"); Object customValidator = this.context.getBean("customValidator");

Loading…
Cancel
Save