Browse Source

Consistently skip unnecessary search on superclasses and empty elements

Issue: SPR-16933
pull/1946/head
Juergen Hoeller 6 years ago
parent
commit
6b3dd0779f
  1. 8
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
  2. 12
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
  3. 18
      spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java
  4. 61
      spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
  5. 67
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

8
spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

@ -120,7 +120,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean @@ -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 @@ -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 @@ -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) {

12
spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java

@ -1,5 +1,5 @@ @@ -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 @@ -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;
}

18
spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java vendored

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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();

61
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

@ -24,6 +24,7 @@ import java.util.Arrays; @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}
}
}

67
spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

@ -346,7 +346,7 @@ public abstract class AnnotationUtils { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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) {

Loading…
Cancel
Save