11/*
2- * Copyright 2012-2020 the original author or authors.
2+ * Copyright 2012-2022 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
5151 *
5252 * @author Madhura Bhave
5353 * @author Phillip Webb
54+ * @author Moritz Halbritter
5455 * @since 1.5.0
5556 */
5657@ SupportedAnnotationTypes ({ "org.springframework.boot.autoconfigure.condition.ConditionalOnClass" ,
5960 "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication" ,
6061 "org.springframework.boot.autoconfigure.AutoConfigureBefore" ,
6162 "org.springframework.boot.autoconfigure.AutoConfigureAfter" ,
62- "org.springframework.boot.autoconfigure.AutoConfigureOrder" })
63+ "org.springframework.boot.autoconfigure.AutoConfigureOrder" ,
64+ "org.springframework.boot.autoconfigure.AutoConfiguration" })
6365public class AutoConfigureAnnotationProcessor extends AbstractProcessor {
6466
6567 protected static final String PROPERTIES_PATH = "META-INF/spring-autoconfigure-metadata.properties" ;
6668
67- private final Map <String , String > annotations ;
68-
69- private final Map <String , ValueExtractor > valueExtractors ;
70-
7169 private final Map <String , String > properties = new TreeMap <>();
7270
73- public AutoConfigureAnnotationProcessor () {
74- Map <String , String > annotations = new LinkedHashMap <>();
75- addAnnotations (annotations );
76- this .annotations = Collections .unmodifiableMap (annotations );
77- Map <String , ValueExtractor > valueExtractors = new LinkedHashMap <>();
78- addValueExtractors (valueExtractors );
79- this .valueExtractors = Collections .unmodifiableMap (valueExtractors );
80- }
71+ private final List <PropertyGenerator > propertyGenerators ;
8172
82- protected void addAnnotations (Map <String , String > annotations ) {
83- annotations .put ("ConditionalOnClass" , "org.springframework.boot.autoconfigure.condition.ConditionalOnClass" );
84- annotations .put ("ConditionalOnBean" , "org.springframework.boot.autoconfigure.condition.ConditionalOnBean" );
85- annotations .put ("ConditionalOnSingleCandidate" ,
86- "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate" );
87- annotations .put ("ConditionalOnWebApplication" ,
88- "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication" );
89- annotations .put ("AutoConfigureBefore" , "org.springframework.boot.autoconfigure.AutoConfigureBefore" );
90- annotations .put ("AutoConfigureAfter" , "org.springframework.boot.autoconfigure.AutoConfigureAfter" );
91- annotations .put ("AutoConfigureOrder" , "org.springframework.boot.autoconfigure.AutoConfigureOrder" );
73+ public AutoConfigureAnnotationProcessor () {
74+ this .propertyGenerators = Collections .unmodifiableList (getPropertyGenerators ());
9275 }
9376
94- private void addValueExtractors (Map <String , ValueExtractor > attributes ) {
95- attributes .put ("ConditionalOnClass" , new OnClassConditionValueExtractor ());
96- attributes .put ("ConditionalOnBean" , new OnBeanConditionValueExtractor ());
97- attributes .put ("ConditionalOnSingleCandidate" , new OnBeanConditionValueExtractor ());
98- attributes .put ("ConditionalOnWebApplication" , ValueExtractor .allFrom ("type" ));
99- attributes .put ("AutoConfigureBefore" , ValueExtractor .allFrom ("value" , "name" ));
100- attributes .put ("AutoConfigureAfter" , ValueExtractor .allFrom ("value" , "name" ));
101- attributes .put ("AutoConfigureOrder" , ValueExtractor .allFrom ("value" ));
77+ protected List <PropertyGenerator > getPropertyGenerators () {
78+ List <PropertyGenerator > generators = new ArrayList <>();
79+ generators .add (PropertyGenerator .of ("ConditionalOnClass" ,
80+ "org.springframework.boot.autoconfigure.condition.ConditionalOnClass" ,
81+ new OnClassConditionValueExtractor ()));
82+ generators .add (PropertyGenerator .of ("ConditionalOnBean" ,
83+ "org.springframework.boot.autoconfigure.condition.ConditionalOnBean" ,
84+ new OnBeanConditionValueExtractor ()));
85+ generators .add (PropertyGenerator .of ("ConditionalOnSingleCandidate" ,
86+ "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate" ,
87+ new OnBeanConditionValueExtractor ()));
88+ generators .add (PropertyGenerator .of ("ConditionalOnWebApplication" ,
89+ "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication" ,
90+ ValueExtractor .allFrom ("type" )));
91+ generators .add (PropertyGenerator .of ("AutoConfigureBefore" ,
92+ "org.springframework.boot.autoconfigure.AutoConfigureBefore" , ValueExtractor .allFrom ("value" , "name" ),
93+ "org.springframework.boot.autoconfigure.AutoConfiguration" ,
94+ ValueExtractor .allFrom ("before" , "beforeName" )));
95+ generators .add (PropertyGenerator .of ("AutoConfigureAfter" ,
96+ "org.springframework.boot.autoconfigure.AutoConfigureAfter" , ValueExtractor .allFrom ("value" , "name" ),
97+ "org.springframework.boot.autoconfigure.AutoConfiguration" ,
98+ ValueExtractor .allFrom ("after" , "afterName" )));
99+ generators .add (PropertyGenerator .of ("AutoConfigureOrder" ,
100+ "org.springframework.boot.autoconfigure.AutoConfigureOrder" , ValueExtractor .allFrom ("value" )));
101+ return generators ;
102102 }
103103
104104 @ Override
@@ -108,8 +108,8 @@ public SourceVersion getSupportedSourceVersion() {
108108
109109 @ Override
110110 public boolean process (Set <? extends TypeElement > annotations , RoundEnvironment roundEnv ) {
111- for (Map . Entry < String , String > entry : this .annotations . entrySet () ) {
112- process (roundEnv , entry . getKey (), entry . getValue () );
111+ for (PropertyGenerator generator : this .propertyGenerators ) {
112+ process (roundEnv , generator );
113113 }
114114 if (roundEnv .processingOver ()) {
115115 try {
@@ -122,22 +122,24 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
122122 return false ;
123123 }
124124
125- private void process (RoundEnvironment roundEnv , String propertyKey , String annotationName ) {
126- TypeElement annotationType = this .processingEnv .getElementUtils ().getTypeElement (annotationName );
127- if (annotationType != null ) {
128- for (Element element : roundEnv .getElementsAnnotatedWith (annotationType )) {
129- processElement (element , propertyKey , annotationName );
125+ private void process (RoundEnvironment roundEnv , PropertyGenerator generator ) {
126+ for (String annotationName : generator .getSupportedAnnotations ()) {
127+ TypeElement annotationType = this .processingEnv .getElementUtils ().getTypeElement (annotationName );
128+ if (annotationType != null ) {
129+ for (Element element : roundEnv .getElementsAnnotatedWith (annotationType )) {
130+ processElement (element , generator , annotationName );
131+ }
130132 }
131133 }
132134 }
133135
134- private void processElement (Element element , String propertyKey , String annotationName ) {
136+ private void processElement (Element element , PropertyGenerator generator , String annotationName ) {
135137 try {
136138 String qualifiedName = Elements .getQualifiedName (element );
137139 AnnotationMirror annotation = getAnnotation (element , annotationName );
138140 if (qualifiedName != null && annotation != null ) {
139- List <Object > values = getValues (propertyKey , annotation );
140- this .properties . put ( qualifiedName + "." + propertyKey , toCommaDelimitedString ( values ) );
141+ List <Object > values = getValues (generator , annotationName , annotation );
142+ generator . applyToProperties ( this .properties , qualifiedName , values );
141143 this .properties .put (qualifiedName , "" );
142144 }
143145 }
@@ -157,17 +159,8 @@ private AnnotationMirror getAnnotation(Element element, String type) {
157159 return null ;
158160 }
159161
160- private String toCommaDelimitedString (List <Object > list ) {
161- StringBuilder result = new StringBuilder ();
162- for (Object item : list ) {
163- result .append ((result .length () != 0 ) ? "," : "" );
164- result .append (item );
165- }
166- return result .toString ();
167- }
168-
169- private List <Object > getValues (String propertyKey , AnnotationMirror annotation ) {
170- ValueExtractor extractor = this .valueExtractors .get (propertyKey );
162+ private List <Object > getValues (PropertyGenerator generator , String annotationName , AnnotationMirror annotation ) {
163+ ValueExtractor extractor = generator .getValueExtractor (annotationName );
171164 if (extractor == null ) {
172165 return Collections .emptyList ();
173166 }
@@ -190,7 +183,7 @@ private void writeProperties() throws IOException {
190183 }
191184
192185 @ FunctionalInterface
193- private interface ValueExtractor {
186+ interface ValueExtractor {
194187
195188 List <Object > getValues (AnnotationMirror annotation );
196189
@@ -245,7 +238,7 @@ public List<Object> getValues(AnnotationMirror annotation) {
245238
246239 }
247240
248- private static class OnBeanConditionValueExtractor extends AbstractValueExtractor {
241+ static class OnBeanConditionValueExtractor extends AbstractValueExtractor {
249242
250243 @ Override
251244 public List <Object > getValues (AnnotationMirror annotation ) {
@@ -263,7 +256,7 @@ public List<Object> getValues(AnnotationMirror annotation) {
263256
264257 }
265258
266- private static class OnClassConditionValueExtractor extends NamedValuesExtractor {
259+ static class OnClassConditionValueExtractor extends NamedValuesExtractor {
267260
268261 OnClassConditionValueExtractor () {
269262 super ("value" , "name" );
@@ -287,4 +280,66 @@ private boolean isSpringClass(String type) {
287280
288281 }
289282
283+ static final class PropertyGenerator {
284+
285+ private final String keyName ;
286+
287+ /**
288+ * Maps from annotation class name -> {@link ValueExtractor}.
289+ */
290+ private final Map <String , ValueExtractor > valueExtractors ;
291+
292+ private PropertyGenerator (String keyName , Map <String , ValueExtractor > valueExtractors ) {
293+ this .keyName = keyName ;
294+ this .valueExtractors = valueExtractors ;
295+ }
296+
297+ Set <String > getSupportedAnnotations () {
298+ return Collections .unmodifiableSet (this .valueExtractors .keySet ());
299+ }
300+
301+ ValueExtractor getValueExtractor (String annotation ) {
302+ return this .valueExtractors .get (annotation );
303+ }
304+
305+ void applyToProperties (Map <String , String > properties , String className , List <Object > annotationValues ) {
306+ mergeProperties (properties , className + "." + this .keyName , toCommaDelimitedString (annotationValues ));
307+ }
308+
309+ private void mergeProperties (Map <String , String > properties , String key , String value ) {
310+ String existingKey = properties .get (key );
311+ if (existingKey == null || existingKey .isEmpty ()) {
312+ properties .put (key , value );
313+ }
314+ else if (!value .isEmpty ()) {
315+ properties .put (key , existingKey + "," + value );
316+ }
317+ }
318+
319+ private String toCommaDelimitedString (List <Object > list ) {
320+ if (list .isEmpty ()) {
321+ return "" ;
322+ }
323+ StringBuilder result = new StringBuilder ();
324+ for (Object item : list ) {
325+ result .append ((result .length () != 0 ) ? "," : "" );
326+ result .append (item );
327+ }
328+ return result .toString ();
329+ }
330+
331+ static PropertyGenerator of (String keyName , String annotation , ValueExtractor valueExtractor ) {
332+ return new PropertyGenerator (keyName , Collections .singletonMap (annotation , valueExtractor ));
333+ }
334+
335+ static PropertyGenerator of (String keyName , String annotation1 , ValueExtractor valueExtractor1 ,
336+ String annotation2 , ValueExtractor valueExtractor2 ) {
337+ Map <String , ValueExtractor > valueExtractors = new LinkedHashMap <>();
338+ valueExtractors .put (annotation1 , valueExtractor1 );
339+ valueExtractors .put (annotation2 , valueExtractor2 );
340+ return new PropertyGenerator (keyName , valueExtractors );
341+ }
342+
343+ }
344+
290345}
0 commit comments