diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java index 7f1d396badf..305ffe9847f 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java @@ -46,6 +46,7 @@ import org.springframework.util.ConcurrentReferenceHashMap; * * @author Phillip Webb * @author Sam Brannen + * @author Greg Taube * @since 5.2 * @see AnnotationTypeMapping */ @@ -178,7 +179,7 @@ final class AnnotationTypeMappings { * @return type mappings for the annotation type */ static AnnotationTypeMappings forAnnotationType(Class annotationType) { - return forAnnotationType(annotationType, new HashSet<>()); + return forAnnotationType(annotationType, RepeatableContainers.standardRepeatables(), AnnotationFilter.PLAIN); } /** @@ -208,7 +209,11 @@ final class AnnotationTypeMappings { static AnnotationTypeMappings forAnnotationType(Class annotationType, RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { - return forAnnotationType(annotationType, repeatableContainers, annotationFilter, new HashSet<>()); + Cache cache = getCache(repeatableContainers, annotationFilter); + if (cache != null) { + return cache.get(annotationType); + } + return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType, new HashSet<>()); } /** @@ -227,18 +232,28 @@ final class AnnotationTypeMappings { RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter, Set> visitedAnnotationTypes) { - if (repeatableContainers == RepeatableContainers.standardRepeatables()) { - return standardRepeatablesCache.computeIfAbsent(annotationFilter, - key -> new Cache(repeatableContainers, key)).get(annotationType, visitedAnnotationTypes); - } - if (repeatableContainers == RepeatableContainers.none()) { - return noRepeatablesCache.computeIfAbsent(annotationFilter, - key -> new Cache(repeatableContainers, key)).get(annotationType, visitedAnnotationTypes); + Cache cache = getCache(repeatableContainers, annotationFilter); + if (cache != null) { + return cache.get(annotationType, visitedAnnotationTypes); } return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType, visitedAnnotationTypes); } + private static @Nullable Cache getCache( + RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { + + if (repeatableContainers == RepeatableContainers.standardRepeatables()) { + return standardRepeatablesCache.computeIfAbsent(annotationFilter, + key -> new Cache(repeatableContainers, key)); + } + if (repeatableContainers == RepeatableContainers.none()) { + return noRepeatablesCache.computeIfAbsent(annotationFilter, + key -> new Cache(repeatableContainers, key)); + } + return null; + } + static void clearCache() { standardRepeatablesCache.clear(); noRepeatablesCache.clear(); @@ -277,6 +292,17 @@ final class AnnotationTypeMappings { AnnotationTypeMappings get(Class annotationType, Set> visitedAnnotationTypes) { + return getOrCreate(annotationType, visitedAnnotationTypes); + } + + AnnotationTypeMappings get(Class annotationType) { + AnnotationTypeMappings result = this.mappings.get(annotationType); + return (result != null ? result : getOrCreate(annotationType, new HashSet<>())); + } + + private AnnotationTypeMappings getOrCreate(Class annotationType, + Set> visitedAnnotationTypes) { + AnnotationTypeMappings result = this.mappings.get(annotationType); if (result != null) { return result; diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java index 78a1e3f62fd..7cd679bbb3a 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java @@ -47,6 +47,13 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ class AnnotationTypeMappingsTests { + @Test + void forAnnotationTypeWhenCalledTwiceReturnsCachedInstance() { + AnnotationTypeMappings first = AnnotationTypeMappings.forAnnotationType(SimpleAnnotation.class); + AnnotationTypeMappings second = AnnotationTypeMappings.forAnnotationType(SimpleAnnotation.class); + assertThat(second).isSameAs(first); + } + @Test void forAnnotationTypeWhenNoMetaAnnotationsReturnsMappings() { AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(SimpleAnnotation.class);