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