Support customer repeatable containers in type map
Update `AnnotationTypeMappings` so that a custom `RepeatableContainers` instances can be used. Prior to this commit, only standard repeatables were used when reading the annotations. This works in most situations, but causes regressions for some `AnnotationUtils` methods. Fixed gh-23856
This commit is contained in:
parent
f8b875d2d8
commit
013ec6abdb
|
|
@ -47,15 +47,22 @@ final class AnnotationTypeMappings {
|
|||
|
||||
private static final IntrospectionFailureLogger failureLogger = IntrospectionFailureLogger.DEBUG;
|
||||
|
||||
private static final Map<AnnotationFilter, Cache> cache = new ConcurrentReferenceHashMap<>();
|
||||
private static final Map<AnnotationFilter, Cache> standardRepeatablesCache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private static final Map<AnnotationFilter, Cache> noRepeatablesCache = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
|
||||
private final RepeatableContainers repeatableContainers;
|
||||
|
||||
private final AnnotationFilter filter;
|
||||
|
||||
private final List<AnnotationTypeMapping> mappings;
|
||||
|
||||
|
||||
private AnnotationTypeMappings(AnnotationFilter filter, Class<? extends Annotation> annotationType) {
|
||||
private AnnotationTypeMappings(RepeatableContainers repeatableContainers,
|
||||
AnnotationFilter filter, Class<? extends Annotation> annotationType) {
|
||||
|
||||
this.repeatableContainers = repeatableContainers;
|
||||
this.filter = filter;
|
||||
this.mappings = new ArrayList<>();
|
||||
addAllMappings(annotationType);
|
||||
|
|
@ -80,7 +87,7 @@ final class AnnotationTypeMappings {
|
|||
if (!isMappable(source, metaAnnotation)) {
|
||||
continue;
|
||||
}
|
||||
Annotation[] repeatedAnnotations = RepeatableContainers.standardRepeatables()
|
||||
Annotation[] repeatedAnnotations = this.repeatableContainers
|
||||
.findRepeatedAnnotations(metaAnnotation);
|
||||
if (repeatedAnnotations != null) {
|
||||
for (Annotation repeatedAnnotation : repeatedAnnotations) {
|
||||
|
|
@ -178,11 +185,37 @@ final class AnnotationTypeMappings {
|
|||
static AnnotationTypeMappings forAnnotationType(
|
||||
Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter) {
|
||||
|
||||
return cache.computeIfAbsent(annotationFilter, Cache::new).get(annotationType);
|
||||
return forAnnotationType(annotationType,
|
||||
RepeatableContainers.standardRepeatables(), annotationFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link AnnotationTypeMappings} for the specified annotation type.
|
||||
* @param annotationType the source annotation type
|
||||
* @param annotationFilter the annotation filter used to limit which
|
||||
* annotations are considered
|
||||
* @return type mappings for the annotation type
|
||||
*/
|
||||
static AnnotationTypeMappings forAnnotationType(
|
||||
Class<? extends Annotation> annotationType,
|
||||
RepeatableContainers repeatableContainers,
|
||||
AnnotationFilter annotationFilter) {
|
||||
|
||||
if (repeatableContainers == RepeatableContainers.standardRepeatables()) {
|
||||
return standardRepeatablesCache.computeIfAbsent(annotationFilter,
|
||||
key -> new Cache(repeatableContainers, key)).get(annotationType);
|
||||
}
|
||||
if (repeatableContainers == RepeatableContainers.none()) {
|
||||
return noRepeatablesCache.computeIfAbsent(annotationFilter,
|
||||
key -> new Cache(repeatableContainers, key)).get(annotationType);
|
||||
}
|
||||
return new AnnotationTypeMappings(repeatableContainers, annotationFilter,
|
||||
annotationType);
|
||||
}
|
||||
|
||||
static void clearCache() {
|
||||
cache.clear();
|
||||
standardRepeatablesCache.clear();
|
||||
noRepeatablesCache.clear();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -191,6 +224,8 @@ final class AnnotationTypeMappings {
|
|||
*/
|
||||
private static class Cache {
|
||||
|
||||
private final RepeatableContainers repeatableContainers;
|
||||
|
||||
private final AnnotationFilter filter;
|
||||
|
||||
private final Map<Class<? extends Annotation>, AnnotationTypeMappings> mappings;
|
||||
|
|
@ -199,7 +234,8 @@ final class AnnotationTypeMappings {
|
|||
* Create a cache instance with the specified filter.
|
||||
* @param filter the annotation filter
|
||||
*/
|
||||
Cache(AnnotationFilter filter) {
|
||||
Cache(RepeatableContainers repeatableContainers, AnnotationFilter filter) {
|
||||
this.repeatableContainers = repeatableContainers;
|
||||
this.filter = filter;
|
||||
this.mappings = new ConcurrentReferenceHashMap<>();
|
||||
}
|
||||
|
|
@ -214,7 +250,7 @@ final class AnnotationTypeMappings {
|
|||
}
|
||||
|
||||
AnnotationTypeMappings createMappings(Class<? extends Annotation> annotationType) {
|
||||
return new AnnotationTypeMappings(this.filter, annotationType);
|
||||
return new AnnotationTypeMappings(this.repeatableContainers, this.filter, annotationType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -413,7 +413,7 @@ final class TypeMappedAnnotations implements MergedAnnotations {
|
|||
return doWithAnnotations(type, aggregateIndex, source, repeatedAnnotations);
|
||||
}
|
||||
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(
|
||||
annotation.annotationType(), annotationFilter);
|
||||
annotation.annotationType(), repeatableContainers, annotationFilter);
|
||||
for (int i = 0; i < mappings.size(); i++) {
|
||||
AnnotationTypeMapping mapping = mappings.get(i);
|
||||
if (isMappingForType(mapping, annotationFilter, this.requiredType)) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import javax.annotation.Nonnull;
|
|||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
|
|
@ -974,7 +973,6 @@ class AnnotationUtilsTests {
|
|||
}
|
||||
|
||||
@Test // gh-23856
|
||||
@Disabled("disabled until gh-23856 is resolved")
|
||||
void findAnnotationFindsRepeatableContainerOnComposedAnnotationMetaAnnotatedWithRepeatableAnnotationsOnMethod() throws NoSuchMethodException {
|
||||
Method method = getClass().getDeclaredMethod("methodWithComposedAnnotationMetaAnnotatedWithRepeatableAnnotations");
|
||||
MyRepeatableContainer annotation = AnnotationUtils.findAnnotation(method, MyRepeatableContainer.class);
|
||||
|
|
|
|||
Loading…
Reference in New Issue