Browse Source

Merge branch '5.2.x'

pull/25495/head
Sam Brannen 6 years ago
parent
commit
f28918e91d
  1. 28
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java
  2. 6
      spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java
  3. 16
      spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java
  4. 51
      spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.java

28
spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMappings.java

@ -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() {

6
spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java

@ -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);
} }
/** /**

16
spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java

@ -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) {

51
spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.java

@ -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 {
}
} }

Loading…
Cancel
Save