Merge branch '5.2.x'
This commit is contained in:
@@ -30,7 +30,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
|
|||||||
* Provides {@link AnnotationTypeMapping} information for a single source
|
* Provides {@link AnnotationTypeMapping} information for a single source
|
||||||
* annotation type. Performs a recursive breadth first crawl of all
|
* annotation type. Performs a recursive breadth first crawl of all
|
||||||
* meta-annotations to ultimately provide a quick way to map the attributes of
|
* meta-annotations to ultimately provide a quick way to map the attributes of
|
||||||
* root {@link Annotation}.
|
* a root {@link Annotation}.
|
||||||
*
|
*
|
||||||
* <p>Supports convention based merging of meta-annotations as well as implicit
|
* <p>Supports convention based merging of meta-annotations as well as implicit
|
||||||
* and explicit {@link AliasFor @AliasFor} aliases. Also provides information
|
* and explicit {@link AliasFor @AliasFor} aliases. Also provides information
|
||||||
@@ -81,17 +81,15 @@ final class AnnotationTypeMappings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source) {
|
private void addMetaAnnotationsToQueue(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source) {
|
||||||
Annotation[] metaAnnotations =
|
Annotation[] metaAnnotations = AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
|
||||||
AnnotationsScanner.getDeclaredAnnotations(source.getAnnotationType(), false);
|
|
||||||
for (Annotation metaAnnotation : metaAnnotations) {
|
for (Annotation metaAnnotation : metaAnnotations) {
|
||||||
if (!isMappable(source, metaAnnotation)) {
|
if (!isMappable(source, metaAnnotation)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Annotation[] repeatedAnnotations = this.repeatableContainers
|
Annotation[] repeatedAnnotations = this.repeatableContainers.findRepeatedAnnotations(metaAnnotation);
|
||||||
.findRepeatedAnnotations(metaAnnotation);
|
|
||||||
if (repeatedAnnotations != null) {
|
if (repeatedAnnotations != null) {
|
||||||
for (Annotation repeatedAnnotation : repeatedAnnotations) {
|
for (Annotation repeatedAnnotation : repeatedAnnotations) {
|
||||||
if (!isMappable(source, metaAnnotation)) {
|
if (!isMappable(source, repeatedAnnotation)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addIfPossible(queue, source, repeatedAnnotation);
|
addIfPossible(queue, source, repeatedAnnotation);
|
||||||
@@ -103,9 +101,7 @@ final class AnnotationTypeMappings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addIfPossible(Deque<AnnotationTypeMapping> queue,
|
private void addIfPossible(Deque<AnnotationTypeMapping> queue, AnnotationTypeMapping source, Annotation ann) {
|
||||||
AnnotationTypeMapping source, Annotation ann) {
|
|
||||||
|
|
||||||
addIfPossible(queue, source, ann.annotationType(), ann);
|
addIfPossible(queue, source, ann.annotationType(), ann);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,21 +179,20 @@ final class AnnotationTypeMappings {
|
|||||||
static AnnotationTypeMappings forAnnotationType(
|
static AnnotationTypeMappings forAnnotationType(
|
||||||
Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter) {
|
Class<? extends Annotation> annotationType, AnnotationFilter annotationFilter) {
|
||||||
|
|
||||||
return forAnnotationType(annotationType,
|
return forAnnotationType(annotationType, RepeatableContainers.standardRepeatables(), annotationFilter);
|
||||||
RepeatableContainers.standardRepeatables(), annotationFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@link AnnotationTypeMappings} for the specified annotation type.
|
* Create {@link AnnotationTypeMappings} for the specified annotation type.
|
||||||
* @param annotationType the source annotation type
|
* @param annotationType the source annotation type
|
||||||
|
* @param repeatableContainers the repeatable containers that may be used by
|
||||||
|
* the meta-annotations
|
||||||
* @param annotationFilter the annotation filter used to limit which
|
* @param annotationFilter the annotation filter used to limit which
|
||||||
* annotations are considered
|
* annotations are considered
|
||||||
* @return type mappings for the annotation type
|
* @return type mappings for the annotation type
|
||||||
*/
|
*/
|
||||||
static AnnotationTypeMappings forAnnotationType(
|
static AnnotationTypeMappings forAnnotationType(Class<? extends Annotation> annotationType,
|
||||||
Class<? extends Annotation> annotationType,
|
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
|
||||||
RepeatableContainers repeatableContainers,
|
|
||||||
AnnotationFilter annotationFilter) {
|
|
||||||
|
|
||||||
if (repeatableContainers == RepeatableContainers.standardRepeatables()) {
|
if (repeatableContainers == RepeatableContainers.standardRepeatables()) {
|
||||||
return standardRepeatablesCache.computeIfAbsent(annotationFilter,
|
return standardRepeatablesCache.computeIfAbsent(annotationFilter,
|
||||||
@@ -207,8 +202,7 @@ final class AnnotationTypeMappings {
|
|||||||
return noRepeatablesCache.computeIfAbsent(annotationFilter,
|
return noRepeatablesCache.computeIfAbsent(annotationFilter,
|
||||||
key -> new Cache(repeatableContainers, key)).get(annotationType);
|
key -> new Cache(repeatableContainers, key)).get(annotationType);
|
||||||
}
|
}
|
||||||
return new AnnotationTypeMappings(repeatableContainers, annotationFilter,
|
return new AnnotationTypeMappings(repeatableContainers, annotationFilter, annotationType);
|
||||||
annotationType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearCache() {
|
static void clearCache() {
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
|||||||
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
||||||
RepeatableContainers repeatableContainers) {
|
RepeatableContainers repeatableContainers) {
|
||||||
|
|
||||||
return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN);
|
return from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,7 +340,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
|||||||
* @param annotationFilter an annotation filter used to restrict the
|
* @param annotationFilter an annotation filter used to restrict the
|
||||||
* annotations considered
|
* annotations considered
|
||||||
* @return a {@link MergedAnnotations} instance containing the merged
|
* @return a {@link MergedAnnotations} instance containing the merged
|
||||||
* element annotations
|
* annotations for the supplied element
|
||||||
*/
|
*/
|
||||||
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
||||||
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
|
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
|
||||||
@@ -386,7 +386,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
|||||||
* @return a {@link MergedAnnotations} instance containing the annotations
|
* @return a {@link MergedAnnotations} instance containing the annotations
|
||||||
*/
|
*/
|
||||||
static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers) {
|
static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers) {
|
||||||
return TypeMappedAnnotations.from(source, annotations, repeatableContainers, AnnotationFilter.PLAIN);
|
return from(source, annotations, repeatableContainers, AnnotationFilter.PLAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -38,6 +39,7 @@ import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets.Mirr
|
|||||||
import org.springframework.lang.UsesSunMisc;
|
import org.springframework.lang.UsesSunMisc;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
@@ -83,6 +85,14 @@ class AnnotationTypeMappingsTests {
|
|||||||
WithRepeatedMetaAnnotations.class, Repeating.class, Repeating.class);
|
WithRepeatedMetaAnnotations.class, Repeating.class, Repeating.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void forAnnotationTypeWhenRepeatableMetaAnnotationIsFiltered() {
|
||||||
|
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(WithRepeatedMetaAnnotations.class,
|
||||||
|
Repeating.class.getName()::equals);
|
||||||
|
assertThat(getAll(mappings)).flatExtracting(AnnotationTypeMapping::getAnnotationType)
|
||||||
|
.containsExactly(WithRepeatedMetaAnnotations.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void forAnnotationTypeWhenSelfAnnotatedReturnsMapping() {
|
void forAnnotationTypeWhenSelfAnnotatedReturnsMapping() {
|
||||||
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(SelfAnnotated.class);
|
AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(SelfAnnotated.class);
|
||||||
@@ -500,11 +510,7 @@ class AnnotationTypeMappingsTests {
|
|||||||
private List<AnnotationTypeMapping> getAll(AnnotationTypeMappings mappings) {
|
private List<AnnotationTypeMapping> getAll(AnnotationTypeMappings mappings) {
|
||||||
// AnnotationTypeMappings does not implement Iterable so we don't create
|
// AnnotationTypeMappings does not implement Iterable so we don't create
|
||||||
// too many garbage Iterators
|
// too many garbage Iterators
|
||||||
List<AnnotationTypeMapping> result = new ArrayList<>(mappings.size());
|
return IntStream.range(0, mappings.size()).mapToObj(mappings::get).collect(toList());
|
||||||
for (int i = 0; i < mappings.size(); i++) {
|
|
||||||
result.add(mappings.get(i));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getNames(MirrorSet mirrorSet) {
|
private List<String> getNames(MirrorSet mirrorSet) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,6 +25,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.assertj.core.api.ThrowableTypeAssert;
|
import org.assertj.core.api.ThrowableTypeAssert;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -222,14 +223,35 @@ class MergedAnnotationsRepeatableAnnotationTests {
|
|||||||
"B", "C");
|
"B", "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
private <A extends Annotation> Set<A> getAnnotations(
|
@Test
|
||||||
Class<? extends Annotation> container, Class<A> repeatable,
|
void typeHierarchyAnnotationsWithLocalComposedAnnotationWhoseRepeatableMetaAnnotationsAreFiltered() {
|
||||||
SearchStrategy searchStrategy, AnnotatedElement element) {
|
Class<WithRepeatedMetaAnnotationsClass> element = WithRepeatedMetaAnnotationsClass.class;
|
||||||
|
SearchStrategy searchStrategy = SearchStrategy.TYPE_HIERARCHY;
|
||||||
|
AnnotationFilter annotationFilter = PeteRepeat.class.getName()::equals;
|
||||||
|
|
||||||
|
Set<PeteRepeat> annotations = getAnnotations(null, PeteRepeat.class, searchStrategy, element, annotationFilter);
|
||||||
|
assertThat(annotations).isEmpty();
|
||||||
|
|
||||||
|
MergedAnnotations mergedAnnotations = MergedAnnotations.from(element, searchStrategy,
|
||||||
|
RepeatableContainers.standardRepeatables(), annotationFilter);
|
||||||
|
Stream<Class<? extends Annotation>> annotationTypes = mergedAnnotations.stream()
|
||||||
|
.map(MergedAnnotation::synthesize)
|
||||||
|
.map(Annotation::annotationType);
|
||||||
|
assertThat(annotationTypes).containsExactly(WithRepeatedMetaAnnotations.class, Noninherited.class, Noninherited.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <A extends Annotation> Set<A> getAnnotations(Class<? extends Annotation> container,
|
||||||
|
Class<A> repeatable, SearchStrategy searchStrategy, AnnotatedElement element) {
|
||||||
|
|
||||||
|
return getAnnotations(container, repeatable, searchStrategy, element, AnnotationFilter.PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <A extends Annotation> Set<A> getAnnotations(Class<? extends Annotation> container,
|
||||||
|
Class<A> repeatable, SearchStrategy searchStrategy, AnnotatedElement element, AnnotationFilter annotationFilter) {
|
||||||
|
|
||||||
RepeatableContainers containers = RepeatableContainers.of(repeatable, container);
|
RepeatableContainers containers = RepeatableContainers.of(repeatable, container);
|
||||||
MergedAnnotations annotations = MergedAnnotations.from(element,
|
MergedAnnotations annotations = MergedAnnotations.from(element, searchStrategy, containers, annotationFilter);
|
||||||
searchStrategy, containers, AnnotationFilter.PLAIN);
|
return annotations.stream(repeatable).collect(MergedAnnotationCollectors.toAnnotationSet());
|
||||||
return annotations.stream(repeatable).collect(
|
|
||||||
MergedAnnotationCollectors.toAnnotationSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nonRepeatableRequirements(Exception ex) {
|
private void nonRepeatableRequirements(Exception ex) {
|
||||||
@@ -414,4 +436,17 @@ class MergedAnnotationsRepeatableAnnotationTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@PeteRepeat("A")
|
||||||
|
@PeteRepeat("B")
|
||||||
|
@interface WithRepeatedMetaAnnotations {
|
||||||
|
}
|
||||||
|
|
||||||
|
@WithRepeatedMetaAnnotations
|
||||||
|
@PeteRepeat("C")
|
||||||
|
@Noninherited("X")
|
||||||
|
@Noninherited("Y")
|
||||||
|
static class WithRepeatedMetaAnnotationsClass {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user