|
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