|
17 | 17 | package org.springframework.context.annotation;
|
18 | 18 |
|
19 | 19 | import java.io.IOException;
|
20 |
| -import java.lang.annotation.Annotation; |
21 |
| -import java.util.ArrayList; |
| 20 | +import java.util.Arrays; |
22 | 21 | import java.util.Collections;
|
23 | 22 | import java.util.Comparator;
|
24 | 23 | import java.util.HashMap;
|
| 24 | +import java.util.HashSet; |
25 | 25 | import java.util.Iterator;
|
26 | 26 | import java.util.LinkedHashSet;
|
27 |
| -import java.util.List; |
28 | 27 | import java.util.Map;
|
29 | 28 | import java.util.Set;
|
30 | 29 | import java.util.Stack;
|
@@ -222,10 +221,9 @@ protected AnnotationMetadata doProcessConfigurationClass(
|
222 | 221 | }
|
223 | 222 |
|
224 | 223 | // process any @Import annotations
|
225 |
| - List<AnnotationAttributes> imports = |
226 |
| - findAllAnnotationAttributes(Import.class, metadata.getClassName(), true); |
227 |
| - for (AnnotationAttributes importAnno : imports) { |
228 |
| - processImport(configClass, importAnno.getStringArray("value"), true); |
| 224 | + Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>()); |
| 225 | + if (imports != null && !imports.isEmpty()) { |
| 226 | + processImport(configClass, imports.toArray(new String[imports.size()]), true); |
229 | 227 | }
|
230 | 228 |
|
231 | 229 | // process any @ImportResource annotations
|
@@ -265,45 +263,36 @@ protected AnnotationMetadata doProcessConfigurationClass(
|
265 | 263 | }
|
266 | 264 |
|
267 | 265 | /**
|
268 |
| - * Return a list of attribute maps for all declarations of the given annotation |
269 |
| - * on the given annotated class using the given MetadataReaderFactory to introspect |
270 |
| - * annotation metadata. Meta-annotations are ordered first in the list, and if the |
271 |
| - * target annotation is declared directly on the class, its map of attributes will be |
272 |
| - * ordered last in the list. |
273 |
| - * @param targetAnnotation the annotation to search for, both locally and as a meta-annotation |
274 |
| - * @param annotatedClassName the class to inspect |
275 |
| - * @param classValuesAsString whether class attributes should be returned as strings |
| 266 | + * Recursively collect all declared {@code @Import} values. Unlike most |
| 267 | + * meta-annotations it is valid to have several {@code @Import}s declared with |
| 268 | + * different values, the usual process or returning values from the first |
| 269 | + * meta-annotation on a class is not sufficient. |
| 270 | + * <p>For example, it is common for a {@code @Configuration} class to declare direct |
| 271 | + * {@code @Import}s in addition to meta-imports originating from an {@code @Enable} |
| 272 | + * annotation. |
| 273 | + * @param className the class name to search |
| 274 | + * @param imports the imports collected so far or {@code null} |
| 275 | + * @param visited used to track visited classes to prevent infinite recursion (must not be null) |
| 276 | + * @return a set of all {@link Import#value() import values} or {@code null} |
| 277 | + * @throws IOException if there is any problem reading metadata from the named class |
276 | 278 | */
|
277 |
| - private List<AnnotationAttributes> findAllAnnotationAttributes( |
278 |
| - Class<? extends Annotation> targetAnnotation, String annotatedClassName, |
279 |
| - boolean classValuesAsString) throws IOException { |
280 |
| - |
281 |
| - List<AnnotationAttributes> allAttribs = new ArrayList<AnnotationAttributes>(); |
282 |
| - |
283 |
| - MetadataReader reader = this.metadataReaderFactory.getMetadataReader(annotatedClassName); |
284 |
| - AnnotationMetadata metadata = reader.getAnnotationMetadata(); |
285 |
| - String targetAnnotationType = targetAnnotation.getName(); |
286 |
| - |
287 |
| - for (String annotationType : metadata.getAnnotationTypes()) { |
288 |
| - if (annotationType.equals(targetAnnotationType)) { |
289 |
| - continue; |
| 279 | + private Set<String> getImports(String className, Set<String> imports, |
| 280 | + Set<String> visited) throws IOException { |
| 281 | + if (visited.add(className)) { |
| 282 | + AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata(); |
| 283 | + Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true); |
| 284 | + if (attributes != null) { |
| 285 | + String[] value = (String[]) attributes.get("value"); |
| 286 | + if (value != null && value.length > 0) { |
| 287 | + imports = (imports == null ? new LinkedHashSet<String>() : imports); |
| 288 | + imports.addAll(Arrays.asList(value)); |
| 289 | + } |
290 | 290 | }
|
291 |
| - AnnotationMetadata metaAnnotations = |
292 |
| - this.metadataReaderFactory.getMetadataReader(annotationType).getAnnotationMetadata(); |
293 |
| - AnnotationAttributes targetAttribs = |
294 |
| - AnnotationAttributes.fromMap(metaAnnotations.getAnnotationAttributes(targetAnnotationType, classValuesAsString)); |
295 |
| - if (targetAttribs != null) { |
296 |
| - allAttribs.add(targetAttribs); |
| 291 | + for (String annotationType : metadata.getAnnotationTypes()) { |
| 292 | + getImports(annotationType, imports, visited); |
297 | 293 | }
|
298 | 294 | }
|
299 |
| - |
300 |
| - AnnotationAttributes localAttribs = |
301 |
| - AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(targetAnnotationType, classValuesAsString)); |
302 |
| - if (localAttribs != null) { |
303 |
| - allAttribs.add(localAttribs); |
304 |
| - } |
305 |
| - |
306 |
| - return allAttribs; |
| 295 | + return imports; |
307 | 296 | }
|
308 | 297 |
|
309 | 298 | private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException {
|
@@ -440,5 +429,4 @@ public CircularImportProblem(ConfigurationClass attemptedImport, Stack<Configura
|
440 | 429 | new Location(importStack.peek().getResource(), metadata));
|
441 | 430 | }
|
442 | 431 | }
|
443 |
| - |
444 | 432 | }
|
0 commit comments