From 1d31d23e29424ebd8501197c63fb168d1cc942a8 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 4 Aug 2015 16:43:05 -0700 Subject: [PATCH] Add `include` support to @EnableAutoConfiguration Update the `@EnableAutoConfiguration` annotation to include an `include` attribute which can be used to specify specific auto-configuration classes. Primarily added to so that tests can selectively auto-configure without needing to worry about class import order. Fixes gh-3660 --- .../EnableAutoConfiguration.java | 9 ++++++++ ...EnableAutoConfigurationImportSelector.java | 22 ++++++++++++++----- ...eAutoConfigurationImportSelectorTests.java | 13 +++++++++++ ...ationPropertiesAutoConfigurationTests.java | 11 ++++++++-- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java index dca59dca18..ae9fed26b1 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfiguration.java @@ -75,6 +75,15 @@ import org.springframework.core.io.support.SpringFactoriesLoader; AutoConfigurationPackages.Registrar.class }) public @interface EnableAutoConfiguration { + /** + * Include only the specified auto-configuration classes and do not attempt full + * auto-configuration. Using this attribute means that {@code spring.factories} files + * will not be considered. This attribute should not generally be specified in + * production applications, however, it is useful for tests. + * @return the classes to include + */ + Class[] include() default {}; + /** * Exclude specific auto-configuration classes such that they will never be applied. * @return the classes to exclude diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java index bcb27ca79d..37c643c05d 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelector.java @@ -75,14 +75,12 @@ class EnableAutoConfigurationImportSelector implements DeferredImportSelector, + " annotated with @EnableAutoConfiguration?"); // Find all possible auto configuration classes, filtering duplicates - List factories = new ArrayList(new LinkedHashSet( - SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, - this.beanClassLoader))); + List factories = getFactories(attributes); // Remove those specifically excluded Set excluded = new LinkedHashSet(); - excluded.addAll(Arrays.asList(attributes.getStringArray("exclude"))); - excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName"))); + excluded.addAll(asList(attributes, "exclude")); + excluded.addAll(asList(attributes, "excludeName")); excluded.addAll(getExcludeAutoConfigurationsProperty()); factories.removeAll(excluded); ConditionEvaluationReport.get(this.beanFactory).recordExclusions(excluded); @@ -100,6 +98,20 @@ class EnableAutoConfigurationImportSelector implements DeferredImportSelector, } } + private List getFactories(AnnotationAttributes attributes) { + List factories = asList(attributes, "include"); + if (factories.isEmpty()) { + factories = SpringFactoriesLoader.loadFactoryNames( + EnableAutoConfiguration.class, this.beanClassLoader); + } + return new ArrayList(new LinkedHashSet(factories)); + } + + private List asList(AnnotationAttributes attributes, String name) { + String[] value = attributes.getStringArray(name); + return Arrays.asList(value == null ? new String[0] : value); + } + private List getExcludeAutoConfigurationsProperty() { RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(this.environment, "spring.autoconfigure."); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelectorTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelectorTests.java index e24edb5634..4409c769fc 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelectorTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/EnableAutoConfigurationImportSelectorTests.java @@ -148,6 +148,18 @@ public class EnableAutoConfigurationImportSelectorTests { ThymeleafAutoConfiguration.class.getName())); } + @Test + public void classIncludesAreApplied() throws Exception { + given( + this.annotationMetadata.getAnnotationAttributes( + EnableAutoConfiguration.class.getName(), true)).willReturn( + this.annotationAttributes); + given(this.annotationAttributes.getStringArray("include")).willReturn( + new String[] { FreeMarkerAutoConfiguration.class.getName() }); + String[] imports = this.importSelector.selectImports(this.annotationMetadata); + assertThat(imports.length, is(equalTo(1))); + } + private void configureExclusions(String[] classExclusion, String[] nameExclusion, String[] propertyExclusion) { given( @@ -168,4 +180,5 @@ public class EnableAutoConfigurationImportSelectorTests { return SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, getClass().getClassLoader()); } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfigurationTests.java index 9c3c24d1ce..736542dbf6 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/context/ConfigurationPropertiesAutoConfigurationTests.java @@ -18,9 +18,11 @@ package org.springframework.boot.autoconfigure.context; import org.junit.After; import org.junit.Test; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import static org.hamcrest.core.Is.is; @@ -44,8 +46,7 @@ public class ConfigurationPropertiesAutoConfigurationTests { @Test public void processAnnotatedBean() { - load(new Class[] { SampleBean.class, - ConfigurationPropertiesAutoConfiguration.class }, "foo.name:test"); + load(new Class[] { AutoConfigured.class, SampleBean.class }, "foo.name:test"); assertThat(this.context.getBean(SampleBean.class).getName(), is("test")); } @@ -62,6 +63,12 @@ public class ConfigurationPropertiesAutoConfigurationTests { this.context.refresh(); } + @Configuration + @EnableAutoConfiguration(include = ConfigurationPropertiesAutoConfiguration.class) + static class AutoConfigured { + + } + @Component @ConfigurationProperties("foo") static class SampleBean {