From 7c942679ad85f254acaa0318cf07753c65a21716 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 4 Jul 2023 12:49:52 +0100 Subject: [PATCH] Polish 'Switch ImportsContextCustomizer to use MergedAnnotations.search' See gh-36211 --- .../context/ImportsContextCustomizer.java | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizer.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizer.java index 4b8a6a75313..ca5786240bb 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizer.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/ImportsContextCustomizer.java @@ -18,10 +18,9 @@ package org.springframework.boot.test.context; import java.lang.reflect.Constructor; import java.util.Collections; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -41,7 +40,6 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportSelector; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationFilter; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; @@ -52,14 +50,13 @@ import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.util.ReflectionUtils; -import static org.springframework.core.annotation.AnnotationFilter.packages; - /** * {@link ContextCustomizer} to allow {@code @Import} annotations to be used directly on * test classes. * * @author Phillip Webb * @author Andy Wilkinson + * @author Laurent Martelli * @see ImportsContextCustomizerFactory */ class ImportsContextCustomizer implements ContextCustomizer { @@ -218,41 +215,43 @@ class ImportsContextCustomizer implements ContextCustomizer { */ static class ContextCustomizerKey { - private static final AnnotationFilter ANNOTATION_FILTERS = or(packages("java.lang.annotation"), - packages("org.spockframework", "spock"), - or(isEqualTo("kotlin.Metadata"), packages("kotlin.annotation")), packages(("org.junit"))); - - private final Object key; + private static final Set ANNOTATION_FILTERS; + static { + Set annotationFilters = new LinkedHashSet<>(); + annotationFilters.add(AnnotationFilter.PLAIN); + annotationFilters.add("kotlin.Metadata"::equals); + annotationFilters.add(AnnotationFilter.packages("kotlin.annotation")); + annotationFilters.add(AnnotationFilter.packages("org.spockframework", "spock")); + annotationFilters.add(AnnotationFilter.packages("org.junit")); + ANNOTATION_FILTERS = Collections.unmodifiableSet(annotationFilters); + } + private final Set key; ContextCustomizerKey(Class testClass) { - MergedAnnotations mergedAnnotations = MergedAnnotations - .search(MergedAnnotations.SearchStrategy.TYPE_HIERARCHY) - .withAnnotationFilter(ANNOTATION_FILTERS) + MergedAnnotations annotations = MergedAnnotations.search(MergedAnnotations.SearchStrategy.TYPE_HIERARCHY) + .withAnnotationFilter(this::isFilteredAnnotation) .from(testClass); - Set determinedImports = determineImports(mergedAnnotations, testClass); - if (determinedImports != null) { - this.key = determinedImports; - } - else { - this.key = AnnotatedElementUtils.findAllMergedAnnotations(testClass, - mergedAnnotations.stream().map(MergedAnnotation::getType).collect(Collectors.toSet())); - } + Set determinedImports = determineImports(annotations, testClass); + this.key = (determinedImports != null) ? determinedImports : synthesize(annotations); } - private Set determineImports(MergedAnnotations mergedAnnotations, Class testClass) { - AnnotationMetadata testClassMetadata = AnnotationMetadata.introspect(testClass); - return mergedAnnotations.stream(Import.class) - .flatMap((ma) -> Stream.of(ma.getClassArray("value"))) - .map((source) -> determineImports(source, testClassMetadata)) - .reduce(new HashSet<>(), (a, b) -> { - if (a == null || b == null) { + private boolean isFilteredAnnotation(String typeName) { + return ANNOTATION_FILTERS.stream().anyMatch((filter) -> filter.matches(typeName)); + } + + private Set determineImports(MergedAnnotations annotations, Class testClass) { + Set determinedImports = new LinkedHashSet<>(); + AnnotationMetadata metadata = AnnotationMetadata.introspect(testClass); + for (MergedAnnotation annotation : annotations.stream(Import.class).toList()) { + for (Class source : annotation.getClassArray(MergedAnnotation.VALUE)) { + Set determinedSourceImports = determineImports(source, metadata); + if (determinedSourceImports == null) { return null; } - else { - a.add(b); - return a; - } - }); + determinedImports.addAll(determinedSourceImports); + } + } + return determinedImports; } private Set determineImports(Class source, AnnotationMetadata metadata) { @@ -270,6 +269,10 @@ class ImportsContextCustomizer implements ContextCustomizer { return Collections.singleton(source.getName()); } + private Set synthesize(MergedAnnotations annotations) { + return annotations.stream().map(MergedAnnotation::synthesize).collect(Collectors.toSet()); + } + @SuppressWarnings("unchecked") private T instantiate(Class source) { try { @@ -300,12 +303,4 @@ class ImportsContextCustomizer implements ContextCustomizer { } - static AnnotationFilter or(AnnotationFilter... filters) { - return typeName -> Stream.of(filters).anyMatch(filter -> filter.matches(typeName)); - } - - static AnnotationFilter isEqualTo(String expectedTypeName) { - return typeName -> typeName.equals(expectedTypeName); - } - }