From 7872f61bfcf3dd3ef5670eb382927fa02caca98f Mon Sep 17 00:00:00 2001 From: Moritz Halbritter Date: Wed, 23 Feb 2022 13:35:06 +0100 Subject: [PATCH] Add @AutoConfiguration annotation support to the autoconfigure-processor See gh-29907 --- .../AutoConfigurationSorterTests.java | 20 ++- .../AutoConfigureAnnotationProcessor.java | 167 ++++++++++++------ ...AutoConfigureAnnotationProcessorTests.java | 29 ++- .../TestAutoConfiguration.java | 52 ++++++ .../TestAutoConfigurationConfiguration.java | 31 ++++ .../TestAutoConfigureAnnotationProcessor.java | 39 ++-- ...tMergedAutoConfigurationConfiguration.java | 36 ++++ 7 files changed, 301 insertions(+), 73 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationConfiguration.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMergedAutoConfigurationConfiguration.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationSorterTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationSorterTests.java index 93191028ed..aa60c03afb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationSorterTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationSorterTests.java @@ -112,6 +112,15 @@ class AutoConfigurationSorterTests { assertThat(actual).containsExactly(C, B2, A3); } + @Test + void byAutoConfigureAfterAliasForWithProperties() throws Exception { + MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(); + this.autoConfigurationMetadata = getAutoConfigurationMetadata(A3, B2, C); + this.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata); + List actual = this.sorter.getInPriorityOrder(Arrays.asList(A3, B2, C)); + assertThat(actual).containsExactly(C, B2, A3); + } + @Test void byAutoConfigureBefore() { List actual = this.sorter.getInPriorityOrder(Arrays.asList(X, Y, Z)); @@ -124,6 +133,15 @@ class AutoConfigurationSorterTests { assertThat(actual).containsExactly(Z2, Y2, X); } + @Test + void byAutoConfigureBeforeAliasForWithProperties() throws Exception { + MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(); + this.autoConfigurationMetadata = getAutoConfigurationMetadata(X, Y2, Z2); + this.sorter = new AutoConfigurationSorter(readerFactory, this.autoConfigurationMetadata); + List actual = this.sorter.getInPriorityOrder(Arrays.asList(X, Y2, Z2)); + assertThat(actual).containsExactly(Z2, Y2, X); + } + @Test void byAutoConfigureAfterDoubles() { List actual = this.sorter.getInPriorityOrder(Arrays.asList(A, B, C, E)); @@ -273,7 +291,7 @@ class AutoConfigurationSorterTests { } - @AutoConfiguration(after = { AutoConfigureC.class, AutoConfigureD.class, AutoConfigureE.class }) + @AutoConfiguration(after = { AutoConfigureC.class }) static class AutoConfigureB2 { } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java index 3b38f6badc..467541a481 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/main/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -51,6 +51,7 @@ import javax.tools.StandardLocation; * * @author Madhura Bhave * @author Phillip Webb + * @author Moritz Halbritter * @since 1.5.0 */ @SupportedAnnotationTypes({ "org.springframework.boot.autoconfigure.condition.ConditionalOnClass", @@ -59,46 +60,45 @@ import javax.tools.StandardLocation; "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication", "org.springframework.boot.autoconfigure.AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureAfter", - "org.springframework.boot.autoconfigure.AutoConfigureOrder" }) + "org.springframework.boot.autoconfigure.AutoConfigureOrder", + "org.springframework.boot.autoconfigure.AutoConfiguration" }) public class AutoConfigureAnnotationProcessor extends AbstractProcessor { protected static final String PROPERTIES_PATH = "META-INF/spring-autoconfigure-metadata.properties"; - private final Map annotations; - - private final Map valueExtractors; - private final Map properties = new TreeMap<>(); - public AutoConfigureAnnotationProcessor() { - Map annotations = new LinkedHashMap<>(); - addAnnotations(annotations); - this.annotations = Collections.unmodifiableMap(annotations); - Map valueExtractors = new LinkedHashMap<>(); - addValueExtractors(valueExtractors); - this.valueExtractors = Collections.unmodifiableMap(valueExtractors); - } + private final List propertyGenerators; - protected void addAnnotations(Map annotations) { - annotations.put("ConditionalOnClass", "org.springframework.boot.autoconfigure.condition.ConditionalOnClass"); - annotations.put("ConditionalOnBean", "org.springframework.boot.autoconfigure.condition.ConditionalOnBean"); - annotations.put("ConditionalOnSingleCandidate", - "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate"); - annotations.put("ConditionalOnWebApplication", - "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication"); - annotations.put("AutoConfigureBefore", "org.springframework.boot.autoconfigure.AutoConfigureBefore"); - annotations.put("AutoConfigureAfter", "org.springframework.boot.autoconfigure.AutoConfigureAfter"); - annotations.put("AutoConfigureOrder", "org.springframework.boot.autoconfigure.AutoConfigureOrder"); + public AutoConfigureAnnotationProcessor() { + this.propertyGenerators = Collections.unmodifiableList(getPropertyGenerators()); } - private void addValueExtractors(Map attributes) { - attributes.put("ConditionalOnClass", new OnClassConditionValueExtractor()); - attributes.put("ConditionalOnBean", new OnBeanConditionValueExtractor()); - attributes.put("ConditionalOnSingleCandidate", new OnBeanConditionValueExtractor()); - attributes.put("ConditionalOnWebApplication", ValueExtractor.allFrom("type")); - attributes.put("AutoConfigureBefore", ValueExtractor.allFrom("value", "name")); - attributes.put("AutoConfigureAfter", ValueExtractor.allFrom("value", "name")); - attributes.put("AutoConfigureOrder", ValueExtractor.allFrom("value")); + protected List getPropertyGenerators() { + List generators = new ArrayList<>(); + generators.add(PropertyGenerator.of("ConditionalOnClass", + "org.springframework.boot.autoconfigure.condition.ConditionalOnClass", + new OnClassConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnBean", + "org.springframework.boot.autoconfigure.condition.ConditionalOnBean", + new OnBeanConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnSingleCandidate", + "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate", + new OnBeanConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnWebApplication", + "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication", + ValueExtractor.allFrom("type"))); + generators.add(PropertyGenerator.of("AutoConfigureBefore", + "org.springframework.boot.autoconfigure.AutoConfigureBefore", ValueExtractor.allFrom("value", "name"), + "org.springframework.boot.autoconfigure.AutoConfiguration", + ValueExtractor.allFrom("before", "beforeName"))); + generators.add(PropertyGenerator.of("AutoConfigureAfter", + "org.springframework.boot.autoconfigure.AutoConfigureAfter", ValueExtractor.allFrom("value", "name"), + "org.springframework.boot.autoconfigure.AutoConfiguration", + ValueExtractor.allFrom("after", "afterName"))); + generators.add(PropertyGenerator.of("AutoConfigureOrder", + "org.springframework.boot.autoconfigure.AutoConfigureOrder", ValueExtractor.allFrom("value"))); + return generators; } @Override @@ -108,8 +108,8 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - for (Map.Entry entry : this.annotations.entrySet()) { - process(roundEnv, entry.getKey(), entry.getValue()); + for (PropertyGenerator generator : this.propertyGenerators) { + process(roundEnv, generator); } if (roundEnv.processingOver()) { try { @@ -122,22 +122,24 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { return false; } - private void process(RoundEnvironment roundEnv, String propertyKey, String annotationName) { - TypeElement annotationType = this.processingEnv.getElementUtils().getTypeElement(annotationName); - if (annotationType != null) { - for (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) { - processElement(element, propertyKey, annotationName); + private void process(RoundEnvironment roundEnv, PropertyGenerator generator) { + for (String annotationName : generator.getSupportedAnnotations()) { + TypeElement annotationType = this.processingEnv.getElementUtils().getTypeElement(annotationName); + if (annotationType != null) { + for (Element element : roundEnv.getElementsAnnotatedWith(annotationType)) { + processElement(element, generator, annotationName); + } } } } - private void processElement(Element element, String propertyKey, String annotationName) { + private void processElement(Element element, PropertyGenerator generator, String annotationName) { try { String qualifiedName = Elements.getQualifiedName(element); AnnotationMirror annotation = getAnnotation(element, annotationName); if (qualifiedName != null && annotation != null) { - List values = getValues(propertyKey, annotation); - this.properties.put(qualifiedName + "." + propertyKey, toCommaDelimitedString(values)); + List values = getValues(generator, annotationName, annotation); + generator.applyToProperties(this.properties, qualifiedName, values); this.properties.put(qualifiedName, ""); } } @@ -157,17 +159,8 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { return null; } - private String toCommaDelimitedString(List list) { - StringBuilder result = new StringBuilder(); - for (Object item : list) { - result.append((result.length() != 0) ? "," : ""); - result.append(item); - } - return result.toString(); - } - - private List getValues(String propertyKey, AnnotationMirror annotation) { - ValueExtractor extractor = this.valueExtractors.get(propertyKey); + private List getValues(PropertyGenerator generator, String annotationName, AnnotationMirror annotation) { + ValueExtractor extractor = generator.getValueExtractor(annotationName); if (extractor == null) { return Collections.emptyList(); } @@ -190,7 +183,7 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { } @FunctionalInterface - private interface ValueExtractor { + interface ValueExtractor { List getValues(AnnotationMirror annotation); @@ -245,7 +238,7 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { } - private static class OnBeanConditionValueExtractor extends AbstractValueExtractor { + static class OnBeanConditionValueExtractor extends AbstractValueExtractor { @Override public List getValues(AnnotationMirror annotation) { @@ -263,7 +256,7 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { } - private static class OnClassConditionValueExtractor extends NamedValuesExtractor { + static class OnClassConditionValueExtractor extends NamedValuesExtractor { OnClassConditionValueExtractor() { super("value", "name"); @@ -287,4 +280,66 @@ public class AutoConfigureAnnotationProcessor extends AbstractProcessor { } + static final class PropertyGenerator { + + private final String keyName; + + /** + * Maps from annotation class name -> {@link ValueExtractor}. + */ + private final Map valueExtractors; + + private PropertyGenerator(String keyName, Map valueExtractors) { + this.keyName = keyName; + this.valueExtractors = valueExtractors; + } + + Set getSupportedAnnotations() { + return Collections.unmodifiableSet(this.valueExtractors.keySet()); + } + + ValueExtractor getValueExtractor(String annotation) { + return this.valueExtractors.get(annotation); + } + + void applyToProperties(Map properties, String className, List annotationValues) { + mergeProperties(properties, className + "." + this.keyName, toCommaDelimitedString(annotationValues)); + } + + private void mergeProperties(Map properties, String key, String value) { + String existingKey = properties.get(key); + if (existingKey == null || existingKey.isEmpty()) { + properties.put(key, value); + } + else if (!value.isEmpty()) { + properties.put(key, existingKey + "," + value); + } + } + + private String toCommaDelimitedString(List list) { + if (list.isEmpty()) { + return ""; + } + StringBuilder result = new StringBuilder(); + for (Object item : list) { + result.append((result.length() != 0) ? "," : ""); + result.append(item); + } + return result.toString(); + } + + static PropertyGenerator of(String keyName, String annotation, ValueExtractor valueExtractor) { + return new PropertyGenerator(keyName, Collections.singletonMap(annotation, valueExtractor)); + } + + static PropertyGenerator of(String keyName, String annotation1, ValueExtractor valueExtractor1, + String annotation2, ValueExtractor valueExtractor2) { + Map valueExtractors = new LinkedHashMap<>(); + valueExtractors.put(annotation1, valueExtractor1); + valueExtractors.put(annotation2, valueExtractor2); + return new PropertyGenerator(keyName, valueExtractors); + } + + } + } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java index 10f9c4492a..8eb8b9e2a3 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/AutoConfigureAnnotationProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2022 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. @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link AutoConfigureAnnotationProcessor}. * * @author Madhura Bhave + * @author Moritz Halbritter */ class AutoConfigureAnnotationProcessorTests { @@ -97,6 +98,32 @@ class AutoConfigureAnnotationProcessorTests { "123"); } + @Test + void annotatedClassWithAutoConfiguration() throws Exception { + Properties properties = compile(TestAutoConfigurationConfiguration.class); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration", ""); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration.AutoConfigureBefore", + "java.io.InputStream,test.before1,test.before2"); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestAutoConfigurationConfiguration.AutoConfigureAfter", + "java.io.OutputStream,test.after1,test.after2"); + } + + @Test + void annotatedClassWithAutoConfigurationMerged() throws Exception { + Properties properties = compile(TestMergedAutoConfigurationConfiguration.class); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration", ""); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration.AutoConfigureBefore", + "java.io.InputStream,test.before1,test.before2,java.io.ObjectInputStream,test.before3,test.before4"); + assertThat(properties).containsEntry( + "org.springframework.boot.autoconfigureprocessor.TestMergedAutoConfigurationConfiguration.AutoConfigureAfter", + "java.io.OutputStream,test.after1,test.after2,java.io.ObjectOutputStream,test.after3,test.after4"); + } + @Test // gh-19370 void propertiesAreFullRepeatable() throws Exception { String first = new String( diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfiguration.java new file mode 100644 index 0000000000..56176e1bed --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2022 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 + * + * https://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.autoconfigureprocessor; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.core.annotation.AliasFor; + +/** + * Alternative to Spring Boot's {@code @AutoConfiguration} for testing (removes the need + * for a dependency on the real annotation). + * + * @author Moritz Halbritter + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@TestAutoConfigureBefore +@TestAutoConfigureAfter +public @interface TestAutoConfiguration { + + @AliasFor(annotation = TestAutoConfigureBefore.class, attribute = "value") + Class[] before() default {}; + + @AliasFor(annotation = TestAutoConfigureBefore.class, attribute = "name") + String[] beforeName() default {}; + + @AliasFor(annotation = TestAutoConfigureAfter.class, attribute = "value") + Class[] after() default {}; + + @AliasFor(annotation = TestAutoConfigureAfter.class, attribute = "name") + String[] afterName() default {}; + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationConfiguration.java new file mode 100644 index 0000000000..b1405ff3f6 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigurationConfiguration.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2022 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 + * + * https://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.autoconfigureprocessor; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Test @AutoConfiguration aliases for @AutoConfigureBefore and @AutoConfigureAfter. + * + * @author Moritz Halbritter + */ +@TestAutoConfiguration(before = InputStream.class, beforeName = { "test.before1", "test.before2" }, + after = OutputStream.class, afterName = { "test.after1", "test.after2" }) +public class TestAutoConfigurationConfiguration { + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java index bfa249e154..7bf679ef4e 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestAutoConfigureAnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2022 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. @@ -19,7 +19,8 @@ package org.springframework.boot.autoconfigureprocessor; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import javax.annotation.processing.SupportedAnnotationTypes; @@ -35,7 +36,8 @@ import javax.annotation.processing.SupportedAnnotationTypes; "org.springframework.boot.autoconfigureprocessor.TestConditionalOnWebApplication", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureBefore", "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureAfter", - "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder" }) + "org.springframework.boot.autoconfigureprocessor.TestAutoConfigureOrder", + "org.springframework.boot.autoconfigureprocessor.TestAutoConfiguration" }) public class TestAutoConfigureAnnotationProcessor extends AutoConfigureAnnotationProcessor { private final File outputLocation; @@ -45,18 +47,25 @@ public class TestAutoConfigureAnnotationProcessor extends AutoConfigureAnnotatio } @Override - protected void addAnnotations(Map annotations) { - put(annotations, "ConditionalOnClass", TestConditionalOnClass.class); - put(annotations, "ConditionalOnBean", TestConditionalOnBean.class); - put(annotations, "ConditionalOnSingleCandidate", TestConditionalOnSingleCandidate.class); - put(annotations, "ConditionalOnWebApplication", TestConditionalOnWebApplication.class); - put(annotations, "AutoConfigureBefore", TestAutoConfigureBefore.class); - put(annotations, "AutoConfigureAfter", TestAutoConfigureAfter.class); - put(annotations, "AutoConfigureOrder", TestAutoConfigureOrder.class); - } - - private void put(Map annotations, String key, Class value) { - annotations.put(key, value.getName()); + protected List getPropertyGenerators() { + List generators = new ArrayList<>(); + generators.add(PropertyGenerator.of("ConditionalOnClass", TestConditionalOnClass.class.getName(), + new OnClassConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnBean", TestConditionalOnBean.class.getName(), + new OnBeanConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnSingleCandidate", + TestConditionalOnSingleCandidate.class.getName(), new OnBeanConditionValueExtractor())); + generators.add(PropertyGenerator.of("ConditionalOnWebApplication", + TestConditionalOnWebApplication.class.getName(), ValueExtractor.allFrom("type"))); + generators.add(PropertyGenerator.of("AutoConfigureBefore", TestAutoConfigureBefore.class.getName(), + ValueExtractor.allFrom("value", "name"), TestAutoConfiguration.class.getName(), + ValueExtractor.allFrom("before", "beforeName"))); + generators.add(PropertyGenerator.of("AutoConfigureAfter", TestAutoConfigureAfter.class.getName(), + ValueExtractor.allFrom("value", "name"), TestAutoConfiguration.class.getName(), + ValueExtractor.allFrom("after", "afterName"))); + generators.add(PropertyGenerator.of("AutoConfigureOrder", TestAutoConfigureOrder.class.getName(), + ValueExtractor.allFrom("value"))); + return generators; } public Properties getWrittenProperties() throws IOException { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMergedAutoConfigurationConfiguration.java b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMergedAutoConfigurationConfiguration.java new file mode 100644 index 0000000000..fe5a018800 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-autoconfigure-processor/src/test/java/org/springframework/boot/autoconfigureprocessor/TestMergedAutoConfigurationConfiguration.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2022 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 + * + * https://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.autoconfigureprocessor; + +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +/** + * Test @AutoConfiguration aliases together with @AutoConfigureBefore + * and @AutoConfigureAfter. + * + * @author Moritz Halbritter + */ +@TestAutoConfigureBefore(value = InputStream.class, name = { "test.before1", "test.before2" }) +@TestAutoConfigureAfter(value = OutputStream.class, name = { "test.after1", "test.after2" }) +@TestAutoConfiguration(before = ObjectInputStream.class, beforeName = { "test.before3", "test.before4" }, + after = ObjectOutputStream.class, afterName = { "test.after3", "test.after4" }) +public class TestMergedAutoConfigurationConfiguration { + +}