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 7f1d396badf7..305ffe9847f2 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 @@ * * @author Phillip Webb * @author Sam Brannen + * @author Greg Taube * @since 5.2 * @see AnnotationTypeMapping */ @@ -178,7 +179,7 @@ AnnotationTypeMapping get(int index) { * @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 @@ static AnnotationTypeMappings forAnnotationType(Class anno 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,16 +232,26 @@ static AnnotationTypeMappings forAnnotationType(Class anno RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter, Set> 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)).get(annotationType, visitedAnnotationTypes); + key -> new Cache(repeatableContainers, key)); } if (repeatableContainers == RepeatableContainers.none()) { return noRepeatablesCache.computeIfAbsent(annotationFilter, - key -> new Cache(repeatableContainers, key)).get(annotationType, visitedAnnotationTypes); + key -> new Cache(repeatableContainers, key)); } - return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType, - visitedAnnotationTypes); + return null; } static void clearCache() { @@ -277,6 +292,17 @@ private static class Cache { 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 78a1e3f62fd8..7cd679bbb3ae 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 @@ */ 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);