diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 257d925c50..78bd3416dc 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -62,7 +62,6 @@ import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -515,7 +514,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean @Nullable private MergedAnnotation findAutowiredAnnotation(AccessibleObject ao) { - MergedAnnotations annotations = MergedAnnotations.from(ao, SearchStrategy.INHERITED_ANNOTATIONS); + MergedAnnotations annotations = MergedAnnotations.from(ao); for (Class type : this.autowiredAnnotationTypes) { MergedAnnotation annotation = annotations.get(type); if (annotation.isPresent()) { @@ -533,7 +532,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean * @param ann the Autowired annotation * @return whether the annotation indicates that a dependency is required */ - @SuppressWarnings({ "deprecation", "cast" }) + @SuppressWarnings({"deprecation", "cast"}) protected boolean determineRequiredStatus(MergedAnnotation ann) { // The following (AnnotationAttributes) cast is required on JDK 9+. return determineRequiredStatus((AnnotationAttributes) diff --git a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java index a1f0284795..429767cd66 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/annotation/AnnotationJmxAttributeSource.java @@ -35,7 +35,6 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.EmbeddedValueResolver; -import org.springframework.core.annotation.AnnotationFilter; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotationPredicates; import org.springframework.core.annotation.MergedAnnotations; @@ -168,7 +167,7 @@ public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFac Class containerAnnotationType) { return MergedAnnotations.from(annotatedElement, SearchStrategy.TYPE_HIERARCHY, - RepeatableContainers.of(annotationType, containerAnnotationType), AnnotationFilter.PLAIN) + RepeatableContainers.of(annotationType, containerAnnotationType)) .stream(annotationType) .filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex)) .map(MergedAnnotation::withNonMergedAttributes) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index 7f16e5a6aa..05c8c57cb0 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -750,29 +750,25 @@ public abstract class AnnotatedElementUtils { } private static MergedAnnotations getAnnotations(AnnotatedElement element) { - return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, - RepeatableContainers.none(), AnnotationFilter.PLAIN); + return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none()); } private static MergedAnnotations getRepeatableAnnotations(AnnotatedElement element, @Nullable Class containerType, Class annotationType) { RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType); - return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, - repeatableContainers, AnnotationFilter.PLAIN); + return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, repeatableContainers); } private static MergedAnnotations findAnnotations(AnnotatedElement element) { - return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, - RepeatableContainers.none(), AnnotationFilter.PLAIN); + return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()); } private static MergedAnnotations findRepeatableAnnotations(AnnotatedElement element, @Nullable Class containerType, Class annotationType) { RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType); - return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, - repeatableContainers, AnnotationFilter.PLAIN); + return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, repeatableContainers); } @Nullable diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationFilter.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationFilter.java index e9b5c3abde..4807ff9f46 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationFilter.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationFilter.java @@ -40,11 +40,42 @@ public interface AnnotationFilter { */ AnnotationFilter JAVA = packages("java", "javax"); + /** + * {@link AnnotationFilter} that always matches and can be used when no + * relevant annotation types are expected to present at all. + */ + AnnotationFilter ALL = new AnnotationFilter() { + @Override + public boolean matches(Annotation annotation) { + return true; + } + @Override + public boolean matches(Class type) { + return true; + } + @Override + public boolean matches(String typeName) { + return true; + } + @Override + public String toString() { + return "All annotations filtered"; + } + }; + /** * {@link AnnotationFilter} that never matches and can be used when no - * filtering is needed. + * filtering is needed (allowing for any annotation types to be present). */ AnnotationFilter NONE = new AnnotationFilter() { + @Override + public boolean matches(Annotation annotation) { + return false; + } + @Override + public boolean matches(Class type) { + return false; + } @Override public boolean matches(String typeName) { return false; diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 1381f19a78..e5bdb4a7d5 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -112,7 +112,7 @@ public abstract class AnnotationUtils { private static final AnnotationFilter JAVA_LANG_ANNOTATION_FILTER = AnnotationFilter.packages("java.lang.annotation"); - private static Map, Map> defaultValuesCache = + private static final Map, Map> defaultValuesCache = new ConcurrentReferenceHashMap<>(); @@ -126,6 +126,7 @@ public abstract class AnnotationUtils { * if {@code true} is being returned here. * @since 5.2 * @see #isCandidateClass(Class, Class) + * @see #isCandidateClass(Class, String) */ public static boolean isCandidateClass(Class clazz, Collection> annotationTypes) { for (Class annotationType : annotationTypes) { @@ -160,6 +161,7 @@ public abstract class AnnotationUtils { * {@code true} otherwise. Callers will usually perform full method/field introspection * if {@code true} is being returned here. * @since 5.2 + * @see #isCandidateClass(Class, Class) */ public static boolean isCandidateClass(Class clazz, String annotationName) { if (annotationName.startsWith("java.")) { @@ -196,8 +198,7 @@ public abstract class AnnotationUtils { return null; } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(null, new Annotation[] {annotation}, - RepeatableContainers.none(), AnnotationFilter.PLAIN) + return MergedAnnotations.from(annotation, new Annotation[] {annotation}, RepeatableContainers.none()) .get(annotationType).withNonMergedAttributes() .synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null); } @@ -222,8 +223,7 @@ public abstract class AnnotationUtils { return annotatedElement.getAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, - RepeatableContainers.none(), AnnotationFilter.PLAIN) + return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none()) .get(annotationType).withNonMergedAttributes() .synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null); } @@ -375,8 +375,7 @@ public abstract class AnnotationUtils { RepeatableContainers repeatableContainers = (containerAnnotationType != null ? RepeatableContainers.of(annotationType, containerAnnotationType) : RepeatableContainers.standardRepeatables()); - return MergedAnnotations.from(annotatedElement, SearchStrategy.SUPERCLASS, - repeatableContainers, AnnotationFilter.PLAIN) + return MergedAnnotations.from(annotatedElement, SearchStrategy.SUPERCLASS, repeatableContainers) .stream(annotationType) .filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex)) .map(MergedAnnotation::withNonMergedAttributes) @@ -457,8 +456,8 @@ public abstract class AnnotationUtils { RepeatableContainers repeatableContainers = containerAnnotationType != null ? RepeatableContainers.of(annotationType, containerAnnotationType) : RepeatableContainers.standardRepeatables(); - return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT, - repeatableContainers, AnnotationFilter.PLAIN).stream(annotationType) + return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT, repeatableContainers) + .stream(annotationType) .map(MergedAnnotation::withNonMergedAttributes) .collect(MergedAnnotationCollectors.toAnnotationSet()); } @@ -492,8 +491,7 @@ public abstract class AnnotationUtils { return annotatedElement.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, - RepeatableContainers.none(), AnnotationFilter.PLAIN) + return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none()) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } @@ -524,8 +522,7 @@ public abstract class AnnotationUtils { return method.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, - RepeatableContainers.none(), AnnotationFilter.PLAIN) + return MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } @@ -563,8 +560,7 @@ public abstract class AnnotationUtils { return clazz.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, - RepeatableContainers.none(), AnnotationFilter.PLAIN) + return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none()) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } @@ -714,7 +710,7 @@ public abstract class AnnotationUtils { } // Exhaustive retrieval of merged annotations... return MergedAnnotations.from(annotationType, SearchStrategy.INHERITED_ANNOTATIONS, - RepeatableContainers.none(), AnnotationFilter.PLAIN).isPresent(metaAnnotationType); + RepeatableContainers.none()).isPresent(metaAnnotationType); } /** diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java index dcdf0c88e0..d4a89c5131 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java @@ -53,7 +53,6 @@ import org.springframework.lang.Nullable; * * @AliasFor(attribute = "value") * String[] path() default {}; - * * } * * @@ -303,7 +302,24 @@ public interface MergedAnnotations extends Iterable * element annotations */ static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy) { - return from(element, searchStrategy, RepeatableContainers.standardRepeatables(), AnnotationFilter.PLAIN); + return from(element, searchStrategy, RepeatableContainers.standardRepeatables()); + } + + /** + * Create a new {@link MergedAnnotations} instance containing all + * annotations and meta-annotations from the specified element and, + * depending on the {@link SearchStrategy}, related inherited elements. + * @param element the source element + * @param searchStrategy the search strategy to use + * @param repeatableContainers the repeatable containers that may be used by + * the element annotations or the meta-annotations + * @return a {@link MergedAnnotations} instance containing the merged + * element annotations + */ + static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy, + RepeatableContainers repeatableContainers) { + + return TypeMappedAnnotations.from(element, searchStrategy, repeatableContainers, AnnotationFilter.PLAIN); } /** @@ -333,7 +349,7 @@ public interface MergedAnnotations extends Iterable * @see #from(Object, Annotation...) */ static MergedAnnotations from(Annotation... annotations) { - return from(null, annotations); + return from(annotations, annotations); } /** @@ -347,8 +363,23 @@ public interface MergedAnnotations extends Iterable * @see #from(Annotation...) * @see #from(AnnotatedElement) */ - static MergedAnnotations from(@Nullable Object source, Annotation... annotations) { - return from(source, annotations, RepeatableContainers.standardRepeatables(), AnnotationFilter.PLAIN); + static MergedAnnotations from(Object source, Annotation... annotations) { + return from(source, annotations, RepeatableContainers.standardRepeatables()); + } + + /** + * Create a new {@link MergedAnnotations} instance from the specified + * annotations. + * @param source the source for the annotations. This source is used only + * for information and logging. It does not need to actually + * contain the specified annotations, and it will not be searched. + * @param annotations the annotations to include + * @param repeatableContainers the repeatable containers that may be used by + * meta-annotations + * @return a {@link MergedAnnotations} instance containing the annotations + */ + static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers) { + return TypeMappedAnnotations.from(source, annotations, repeatableContainers, AnnotationFilter.PLAIN); } /** @@ -364,7 +395,7 @@ public interface MergedAnnotations extends Iterable * annotations considered * @return a {@link MergedAnnotations} instance containing the annotations */ - static MergedAnnotations from(@Nullable Object source, Annotation[] annotations, + static MergedAnnotations from(Object source, Annotation[] annotations, RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) { return TypeMappedAnnotations.from(source, annotations, repeatableContainers, annotationFilter); diff --git a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotations.java b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotations.java index 09675be62f..8bbbe05007 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotations.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotations.java @@ -40,13 +40,11 @@ import org.springframework.lang.Nullable; */ final class TypeMappedAnnotations implements MergedAnnotations { - private static final AnnotationFilter FILTER_ALL = (annotationType -> true); - /** * Shared instance that can be used when there are no annotations. */ static final MergedAnnotations NONE = new TypeMappedAnnotations( - null, new Annotation[0], RepeatableContainers.none(), FILTER_ALL); + null, new Annotation[0], RepeatableContainers.none(), AnnotationFilter.ALL); @Nullable @@ -180,7 +178,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Override public Stream> stream(Class annotationType) { - if (this.annotationFilter == FILTER_ALL) { + if (this.annotationFilter == AnnotationFilter.ALL) { return Stream.empty(); } return StreamSupport.stream(spliterator(annotationType), false); @@ -188,7 +186,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Override public Stream> stream(String annotationType) { - if (this.annotationFilter == FILTER_ALL) { + if (this.annotationFilter == AnnotationFilter.ALL) { return Stream.empty(); } return StreamSupport.stream(spliterator(annotationType), false); @@ -196,7 +194,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Override public Stream> stream() { - if (this.annotationFilter == FILTER_ALL) { + if (this.annotationFilter == AnnotationFilter.ALL) { return Stream.empty(); } return StreamSupport.stream(spliterator(), false); @@ -204,7 +202,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Override public Iterator> iterator() { - if (this.annotationFilter == FILTER_ALL) { + if (this.annotationFilter == AnnotationFilter.ALL) { return Collections.emptyIterator(); } return Spliterators.iterator(spliterator()); @@ -212,7 +210,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Override public Spliterator> spliterator() { - if (this.annotationFilter == FILTER_ALL) { + if (this.annotationFilter == AnnotationFilter.ALL) { return Collections.> emptyList().spliterator(); } return spliterator(null); @@ -510,8 +508,7 @@ final class TypeMappedAnnotations implements MergedAnnotations { this.annotations = annotations; this.mappings = new AnnotationTypeMappings[annotations.size()]; for (int i = 0; i < annotations.size(); i++) { - this.mappings[i] = AnnotationTypeMappings.forAnnotationType( - annotations.get(i).annotationType()); + this.mappings[i] = AnnotationTypeMappings.forAnnotationType(annotations.get(i).annotationType()); } } @@ -531,8 +528,8 @@ final class TypeMappedAnnotations implements MergedAnnotations { @Nullable MergedAnnotation createMergedAnnotationIfPossible( - int annotationIndex, int mappingIndex, - IntrospectionFailureLogger logger) { + int annotationIndex, int mappingIndex, IntrospectionFailureLogger logger) { + return TypeMappedAnnotation.createIfPossible( this.mappings[annotationIndex].get(mappingIndex), this.source, this.annotations.get(annotationIndex), this.aggregateIndex, logger); diff --git a/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java b/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java index 05205aa837..9678dc4603 100644 --- a/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java @@ -21,7 +21,6 @@ import java.lang.reflect.Modifier; import java.util.Map; import org.springframework.core.annotation.AnnotatedElementUtils; -import org.springframework.core.annotation.AnnotationFilter; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.annotation.RepeatableContainers; @@ -75,11 +74,11 @@ public class StandardMethodMetadata implements MethodMetadata { Assert.notNull(introspectedMethod, "Method must not be null"); this.introspectedMethod = introspectedMethod; this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; - this.mergedAnnotations = MergedAnnotations.from(introspectedMethod, - SearchStrategy.DIRECT, RepeatableContainers.none(), - AnnotationFilter.PLAIN); + this.mergedAnnotations = MergedAnnotations.from( + introspectedMethod, SearchStrategy.DIRECT, RepeatableContainers.none()); } + @Override public MergedAnnotations getAnnotations() { return this.mergedAnnotations;