Avoid synthesizable check for common annotation types

This revision considers any java/javax and org.springframework.lang annotations as not synthesizable upfront, checking not only in isSynthesizable but also at synthesizeAnnotation(Array) level.

Issue: SPR-16933
This commit is contained in:
Juergen Hoeller 2018-07-31 20:54:10 +02:00
parent f8340838b3
commit 6cd9060183
3 changed files with 54 additions and 20 deletions

View File

@ -1226,7 +1226,7 @@ public abstract class AnnotatedElementUtils {
if (AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { if (AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
return false; return false;
} }
if (currentAnnotationType == Nullable.class || currentAnnotationType.getName().startsWith("java")) { if (AnnotationUtils.hasPlainJavaAnnotationsOnly(currentAnnotationType)) {
// @Nullable and standard Java annotations are only meant to have standard Java meta-annotations // @Nullable and standard Java annotations are only meant to have standard Java meta-annotations
// -> not worth searching otherwise. // -> not worth searching otherwise.
return ((annotationType != null && annotationType.getName().startsWith("java")) || return ((annotationType != null && annotationType.getName().startsWith("java")) ||

View File

@ -22,6 +22,7 @@ import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
@ -918,6 +919,29 @@ public abstract class AnnotationUtils {
return metaPresent; return metaPresent;
} }
/**
* Determine if the {@link Annotation} with the supplied name is defined in the
* {@code java.lang.annotation} or {@code org.springframework.lang} package.
* @param annotatedElement the potential annotation type to check
* @return {@code true} if the annotation is in the {@code java.lang.annotation}
* or {@code org.springframework.lang} package
* @since 5.1
*/
static boolean hasPlainJavaAnnotationsOnly(@Nullable Object annotatedElement) {
Class<?> clazz;
if (annotatedElement instanceof Class) {
clazz = (Class<?>) annotatedElement;
}
else if (annotatedElement instanceof Member) {
clazz = ((Member) annotatedElement).getDeclaringClass();
}
else {
return false;
}
String name = clazz.getName();
return (name.startsWith("java") || name.startsWith("org.springframework.lang."));
}
/** /**
* Determine if the supplied {@link Annotation} is defined in the core JDK * Determine if the supplied {@link Annotation} is defined in the core JDK
* {@code java.lang.annotation} package. * {@code java.lang.annotation} package.
@ -1509,7 +1533,7 @@ public abstract class AnnotationUtils {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) { static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {
if (annotation instanceof SynthesizedAnnotation) { if (annotation instanceof SynthesizedAnnotation || hasPlainJavaAnnotationsOnly(annotatedElement)) {
return annotation; return annotation;
} }
@ -1585,7 +1609,7 @@ public abstract class AnnotationUtils {
* @see #synthesizeAnnotation(Annotation, AnnotatedElement) * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
*/ */
public static <A extends Annotation> A synthesizeAnnotation(Class<A> annotationType) { public static <A extends Annotation> A synthesizeAnnotation(Class<A> annotationType) {
return synthesizeAnnotation(Collections.<String, Object> emptyMap(), annotationType, null); return synthesizeAnnotation(Collections.emptyMap(), annotationType, null);
} }
/** /**
@ -1604,8 +1628,10 @@ public abstract class AnnotationUtils {
* @see #synthesizeAnnotation(Annotation, AnnotatedElement) * @see #synthesizeAnnotation(Annotation, AnnotatedElement)
* @see #synthesizeAnnotation(Map, Class, AnnotatedElement) * @see #synthesizeAnnotation(Map, Class, AnnotatedElement)
*/ */
static Annotation[] synthesizeAnnotationArray( static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, @Nullable Object annotatedElement) {
Annotation[] annotations, @Nullable Object annotatedElement) { if (hasPlainJavaAnnotationsOnly(annotatedElement)) {
return annotations;
}
Annotation[] synthesized = (Annotation[]) Array.newInstance( Annotation[] synthesized = (Annotation[]) Array.newInstance(
annotations.getClass().getComponentType(), annotations.length); annotations.getClass().getComponentType(), annotations.length);
@ -1634,7 +1660,9 @@ public abstract class AnnotationUtils {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
static <A extends Annotation> A[] synthesizeAnnotationArray(@Nullable Map<String, Object>[] maps, Class<A> annotationType) { static <A extends Annotation> A[] synthesizeAnnotationArray(
@Nullable Map<String, Object>[] maps, Class<A> annotationType) {
if (maps == null) { if (maps == null) {
return null; return null;
} }
@ -1716,6 +1744,10 @@ public abstract class AnnotationUtils {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static boolean isSynthesizable(Class<? extends Annotation> annotationType) { private static boolean isSynthesizable(Class<? extends Annotation> annotationType) {
if (hasPlainJavaAnnotationsOnly(annotationType)) {
return false;
}
Boolean synthesizable = synthesizableCache.get(annotationType); Boolean synthesizable = synthesizableCache.get(annotationType);
if (synthesizable != null) { if (synthesizable != null) {
return synthesizable; return synthesizable;
@ -1764,7 +1796,7 @@ public abstract class AnnotationUtils {
*/ */
static List<String> getAttributeAliasNames(Method attribute) { static List<String> getAttributeAliasNames(Method attribute) {
AliasDescriptor descriptor = AliasDescriptor.from(attribute); AliasDescriptor descriptor = AliasDescriptor.from(attribute);
return (descriptor != null ? descriptor.getAttributeAliasNames() : Collections.<String> emptyList()); return (descriptor != null ? descriptor.getAttributeAliasNames() : Collections.emptyList());
} }
/** /**

View File

@ -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"); * 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.
@ -64,7 +64,7 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
public void visitEnd() { public void visitEnd() {
super.visitEnd(); super.visitEnd();
Class<?> annotationClass = this.attributes.annotationType(); Class<? extends Annotation> annotationClass = this.attributes.annotationType();
if (annotationClass != null) { if (annotationClass != null) {
List<AnnotationAttributes> attributeList = this.attributesMap.get(this.annotationType); List<AnnotationAttributes> attributeList = this.attributesMap.get(this.annotationType);
if (attributeList == null) { if (attributeList == null) {
@ -73,20 +73,22 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
else { else {
attributeList.add(0, this.attributes); attributeList.add(0, this.attributes);
} }
Set<Annotation> visited = new LinkedHashSet<>(); if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName())) {
Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass); Set<Annotation> visited = new LinkedHashSet<>();
if (!ObjectUtils.isEmpty(metaAnnotations)) { Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass);
for (Annotation metaAnnotation : metaAnnotations) { if (!ObjectUtils.isEmpty(metaAnnotations)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) { for (Annotation metaAnnotation : metaAnnotations) {
recursivelyCollectMetaAnnotations(visited, metaAnnotation); if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) {
recursivelyCollectMetaAnnotations(visited, metaAnnotation);
}
} }
} }
Set<String> metaAnnotationTypeNames = new LinkedHashSet<>(visited.size());
for (Annotation ann : visited) {
metaAnnotationTypeNames.add(ann.annotationType().getName());
}
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
} }
Set<String> metaAnnotationTypeNames = new LinkedHashSet<>(visited.size());
for (Annotation ann : visited) {
metaAnnotationTypeNames.add(ann.annotationType().getName());
}
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
} }
} }