Bypass method traversal for annotation introspection if possible
The isCandidateClass mechanism is consistently used for a bypass check before method traversal attempts. While by default this is only bypassing standard java types, the same mechanism can be used with index metadata which indicates non-presence of certain annotations. See gh-22420
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,6 +28,7 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -151,6 +152,55 @@ public abstract class AnnotationUtils {
|
||||
private static transient Log logger;
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given class is a candidate for carrying one of the specified
|
||||
* annotations (at type, method or field level).
|
||||
* @param clazz the class to introspect
|
||||
* @param annotationTypes the searchable annotation types
|
||||
* @return {@code false} if the class is known to have no such annotations at any level;
|
||||
* {@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, Collection<Class<? extends Annotation>> annotationTypes) {
|
||||
for (Class<? extends Annotation> annotationType : annotationTypes) {
|
||||
if (isCandidateClass(clazz, annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given class is a candidate for carrying the specified annotation
|
||||
* (at type, method or field level).
|
||||
* @param clazz the class to introspect
|
||||
* @param annotationType the searchable annotation type
|
||||
* @return {@code false} if the class is known to have no such annotations at any level;
|
||||
* {@code true} otherwise. Callers will usually perform full method/field introspection
|
||||
* if {@code true} is being returned here.
|
||||
* @since 5.2
|
||||
* @see #isCandidateClass(Class, String)
|
||||
*/
|
||||
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
|
||||
return isCandidateClass(clazz, annotationType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given class is a candidate for carrying the specified annotation
|
||||
* (at type, method or field level).
|
||||
* @param clazz the class to introspect
|
||||
* @param annotationName the fully-qualified name of the searchable annotation type
|
||||
* @return {@code false} if the class is known to have no such annotations at any level;
|
||||
* {@code true} otherwise. Callers will usually perform full method/field introspection
|
||||
* if {@code true} is being returned here.
|
||||
* @since 5.2
|
||||
*/
|
||||
public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
|
||||
return !clazz.getName().startsWith("java");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single {@link Annotation} of {@code annotationType} from the supplied
|
||||
* annotation: either the given annotation itself or a direct meta-annotation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -137,37 +138,41 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
|
||||
@Override
|
||||
public boolean hasAnnotatedMethods(String annotationName) {
|
||||
try {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (!method.isBridge() && method.getAnnotations().length > 0 &&
|
||||
AnnotatedElementUtils.isAnnotated(method, annotationName)) {
|
||||
return true;
|
||||
if (AnnotationUtils.isCandidateClass(getIntrospectedClass(), annotationName)) {
|
||||
try {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (!method.isBridge() && method.getAnnotations().length > 0 &&
|
||||
AnnotatedElementUtils.isAnnotated(method, annotationName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect annotated methods on " + getIntrospectedClass(), ex);
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect annotated methods on " + getIntrospectedClass(), ex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<MethodMetadata> getAnnotatedMethods(String annotationName) {
|
||||
try {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<>(4);
|
||||
for (Method method : methods) {
|
||||
if (!method.isBridge() && method.getAnnotations().length > 0 &&
|
||||
AnnotatedElementUtils.isAnnotated(method, annotationName)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<>(4);
|
||||
if (AnnotationUtils.isCandidateClass(getIntrospectedClass(), annotationName)) {
|
||||
try {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (!method.isBridge() && method.getAnnotations().length > 0 &&
|
||||
AnnotatedElementUtils.isAnnotated(method, annotationName)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotatedMethods;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect annotated methods on " + getIntrospectedClass(), ex);
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalStateException("Failed to introspect annotated methods on " + getIntrospectedClass(), ex);
|
||||
}
|
||||
}
|
||||
return annotatedMethods;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user