Consistently skip unnecessary search on superclasses and empty elements
Issue: SPR-16933
This commit is contained in:
@@ -120,7 +120,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>();
|
||||
private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
|
||||
|
||||
private String requiredParameterName = "required";
|
||||
|
||||
@@ -346,8 +346,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
|
||||
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
|
||||
}
|
||||
else if (nonSyntheticConstructors == 2 && primaryConstructor != null
|
||||
&& defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
|
||||
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
|
||||
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
|
||||
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
|
||||
}
|
||||
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
|
||||
@@ -478,7 +478,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
@Nullable
|
||||
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
|
||||
if (ao.getAnnotations().length > 0) {
|
||||
if (ao.getAnnotations().length > 0) { // autowiring annotations have to be local
|
||||
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
|
||||
if (attributes != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -347,10 +347,12 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
||||
*/
|
||||
@Nullable
|
||||
protected Object findValue(Annotation[] annotationsToSearch) {
|
||||
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
|
||||
if (attr != null) {
|
||||
return extractValue(attr);
|
||||
if (annotationsToSearch.length > 0) { // qualifier annotations have to be local
|
||||
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
|
||||
if (attr != null) {
|
||||
return extractValue(attr);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -52,13 +52,13 @@ public class AnnotationCacheOperationSourceTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void singularAnnotation() throws Exception {
|
||||
public void singularAnnotation() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singular", 1);
|
||||
assertTrue(ops.iterator().next() instanceof CacheableOperation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleAnnotation() throws Exception {
|
||||
public void multipleAnnotation() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multiple", 2);
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
assertTrue(it.next() instanceof CacheableOperation);
|
||||
@@ -66,7 +66,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void caching() throws Exception {
|
||||
public void caching() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "caching", 2);
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
assertTrue(it.next() instanceof CacheableOperation);
|
||||
@@ -74,18 +74,18 @@ public class AnnotationCacheOperationSourceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyCaching() throws Exception {
|
||||
public void emptyCaching() {
|
||||
getOps(AnnotatedClass.class, "emptyCaching", 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singularStereotype() throws Exception {
|
||||
public void singularStereotype() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleStereotype", 1);
|
||||
assertTrue(ops.iterator().next() instanceof CacheEvictOperation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleStereotypes() throws Exception {
|
||||
public void multipleStereotypes() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleStereotype", 3);
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
assertTrue(it.next() instanceof CacheableOperation);
|
||||
@@ -98,7 +98,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleComposedAnnotation() throws Exception {
|
||||
public void singleComposedAnnotation() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleComposed", 2);
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
|
||||
@@ -114,7 +114,7 @@ public class AnnotationCacheOperationSourceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleComposedAnnotations() throws Exception {
|
||||
public void multipleComposedAnnotations() {
|
||||
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 4);
|
||||
Iterator<CacheOperation> it = ops.iterator();
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -854,19 +855,21 @@ public class AnnotatedElementUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
|
||||
List<Annotation> inheritedAnnotations = new ArrayList<>();
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (!declaredAnnotations.contains(annotation)) {
|
||||
inheritedAnnotations.add(annotation);
|
||||
if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
|
||||
Class<?> superclass = ((Class) element).getSuperclass();
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
List<Annotation> inheritedAnnotations = new LinkedList<>();
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (!declaredAnnotations.contains(annotation)) {
|
||||
inheritedAnnotations.add(annotation);
|
||||
}
|
||||
}
|
||||
// Continue searching within inherited annotations
|
||||
result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
|
||||
annotationType, annotationName, containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue searching within inherited annotations
|
||||
result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
|
||||
annotationType, annotationName, containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1126,7 +1129,7 @@ public class AnnotatedElementUtils {
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
while (true) {
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz == null || Object.class == clazz) {
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
break;
|
||||
}
|
||||
Set<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethodsInBaseType(clazz);
|
||||
@@ -1152,23 +1155,23 @@ public class AnnotatedElementUtils {
|
||||
}
|
||||
else if (element instanceof Class) {
|
||||
Class<?> clazz = (Class<?>) element;
|
||||
|
||||
// Search on interfaces
|
||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||
T result = searchWithFindSemantics(ifc, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
if (!Annotation.class.isAssignableFrom(clazz)) {
|
||||
// Search on interfaces
|
||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||
T result = searchWithFindSemantics(ifc, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search on superclass
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
if (superclass != null && Object.class != superclass) {
|
||||
T result = searchWithFindSemantics(superclass, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
// Search on superclass
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
T result = searchWithFindSemantics(superclass, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ public abstract class AnnotationUtils {
|
||||
|
||||
if (annotatedElement instanceof Class) {
|
||||
Class<?> superclass = ((Class<?>) annotatedElement).getSuperclass();
|
||||
if (superclass != null && Object.class != superclass) {
|
||||
if (superclass != null && superclass != Object.class) {
|
||||
return getRepeatableAnnotations(superclass, annotationType, containerAnnotationType);
|
||||
}
|
||||
}
|
||||
@@ -553,7 +553,7 @@ public abstract class AnnotationUtils {
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
while (result == null) {
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz == null || Object.class == clazz) {
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
break;
|
||||
}
|
||||
Set<Method> annotatedMethods = getAnnotatedMethodsInBaseType(clazz);
|
||||
@@ -600,6 +600,35 @@ public abstract class AnnotationUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given method override the given candidate method?
|
||||
* @param method the overriding method
|
||||
* @param candidate the potentially overridden method
|
||||
* @since 5.0.8
|
||||
*/
|
||||
static boolean isOverride(Method method, Method candidate) {
|
||||
if (!candidate.getName().equals(method.getName()) ||
|
||||
candidate.getParameterCount() != method.getParameterCount()) {
|
||||
return false;
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (Arrays.equals(candidate.getParameterTypes(), paramTypes)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
if (paramTypes[i] != ResolvableType.forMethodParameter(candidate, i, method.getDeclaringClass()).resolve()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the methods on the given type with searchable annotations on them.
|
||||
* @param baseType the superclass or interface to search
|
||||
* @return the cached set of annotated methods
|
||||
* @since 5.0.5
|
||||
*/
|
||||
static Set<Method> getAnnotatedMethodsInBaseType(Class<?> baseType) {
|
||||
boolean ifcCheck = baseType.isInterface();
|
||||
if (ifcCheck && ClassUtils.isJavaLanguageInterface(baseType)) {
|
||||
@@ -634,6 +663,13 @@ public abstract class AnnotationUtils {
|
||||
return annotatedMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the specified method has searchable annotations,
|
||||
* i.e. not just {@code java.lang} or {@code org.springframework.lang}
|
||||
* annotations such as {@link Deprecated} and {@link Nullable}.
|
||||
* @param ifcMethod the interface method to check
|
||||
* @@since 5.0.5
|
||||
*/
|
||||
private static boolean hasSearchableAnnotations(Method ifcMethod) {
|
||||
Annotation[] anns = ifcMethod.getAnnotations();
|
||||
if (anns.length == 0) {
|
||||
@@ -648,23 +684,6 @@ public abstract class AnnotationUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isOverride(Method method, Method candidate) {
|
||||
if (!candidate.getName().equals(method.getName()) ||
|
||||
candidate.getParameterCount() != method.getParameterCount()) {
|
||||
return false;
|
||||
}
|
||||
Class<?>[] paramTypes = method.getParameterTypes();
|
||||
if (Arrays.equals(candidate.getParameterTypes(), paramTypes)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
if (paramTypes[i] != ResolvableType.forMethodParameter(candidate, i, method.getDeclaringClass()).resolve()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the
|
||||
* supplied {@link Class}, traversing its interfaces, annotations, and
|
||||
@@ -763,7 +782,7 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
if (superclass == null || Object.class == superclass) {
|
||||
if (superclass == null || superclass == Object.class) {
|
||||
return null;
|
||||
}
|
||||
return findAnnotation(superclass, annotationType, visited);
|
||||
@@ -793,7 +812,7 @@ public abstract class AnnotationUtils {
|
||||
*/
|
||||
@Nullable
|
||||
public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, @Nullable Class<?> clazz) {
|
||||
if (clazz == null || Object.class == clazz) {
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
return null;
|
||||
}
|
||||
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
|
||||
@@ -827,8 +846,10 @@ public abstract class AnnotationUtils {
|
||||
* @see #isAnnotationDeclaredLocally(Class, Class)
|
||||
*/
|
||||
@Nullable
|
||||
public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends Annotation>> annotationTypes, @Nullable Class<?> clazz) {
|
||||
if (clazz == null || Object.class == clazz) {
|
||||
public static Class<?> findAnnotationDeclaringClassForTypes(
|
||||
List<Class<? extends Annotation>> annotationTypes, @Nullable Class<?> clazz) {
|
||||
|
||||
if (clazz == null || clazz == Object.class) {
|
||||
return null;
|
||||
}
|
||||
for (Class<? extends Annotation> annotationType : annotationTypes) {
|
||||
|
||||
Reference in New Issue
Block a user