From 6cd906018373b8760d520cb0982f3869cb53d1d3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 31 Jul 2018 20:54:10 +0200 Subject: [PATCH] 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 --- .../annotation/AnnotatedElementUtils.java | 2 +- .../core/annotation/AnnotationUtils.java | 44 ++++++++++++++++--- .../AnnotationAttributesReadingVisitor.java | 28 ++++++------ 3 files changed, 54 insertions(+), 20 deletions(-) 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 a58e632c9c9..c4bdb1c7821 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 @@ -1226,7 +1226,7 @@ public abstract class AnnotatedElementUtils { if (AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) { 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 // -> not worth searching otherwise. return ((annotationType != null && annotationType.getName().startsWith("java")) || 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 8d189586885..ab0074954f3 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 @@ -22,6 +22,7 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; @@ -918,6 +919,29 @@ public abstract class AnnotationUtils { 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 * {@code java.lang.annotation} package. @@ -1509,7 +1533,7 @@ public abstract class AnnotationUtils { @SuppressWarnings("unchecked") static A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) { - if (annotation instanceof SynthesizedAnnotation) { + if (annotation instanceof SynthesizedAnnotation || hasPlainJavaAnnotationsOnly(annotatedElement)) { return annotation; } @@ -1585,7 +1609,7 @@ public abstract class AnnotationUtils { * @see #synthesizeAnnotation(Annotation, AnnotatedElement) */ public static A synthesizeAnnotation(Class annotationType) { - return synthesizeAnnotation(Collections. emptyMap(), annotationType, null); + return synthesizeAnnotation(Collections.emptyMap(), annotationType, null); } /** @@ -1604,8 +1628,10 @@ public abstract class AnnotationUtils { * @see #synthesizeAnnotation(Annotation, AnnotatedElement) * @see #synthesizeAnnotation(Map, Class, AnnotatedElement) */ - static Annotation[] synthesizeAnnotationArray( - Annotation[] annotations, @Nullable Object annotatedElement) { + static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, @Nullable Object annotatedElement) { + if (hasPlainJavaAnnotationsOnly(annotatedElement)) { + return annotations; + } Annotation[] synthesized = (Annotation[]) Array.newInstance( annotations.getClass().getComponentType(), annotations.length); @@ -1634,7 +1660,9 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") @Nullable - static A[] synthesizeAnnotationArray(@Nullable Map[] maps, Class annotationType) { + static A[] synthesizeAnnotationArray( + @Nullable Map[] maps, Class annotationType) { + if (maps == null) { return null; } @@ -1716,6 +1744,10 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") private static boolean isSynthesizable(Class annotationType) { + if (hasPlainJavaAnnotationsOnly(annotationType)) { + return false; + } + Boolean synthesizable = synthesizableCache.get(annotationType); if (synthesizable != null) { return synthesizable; @@ -1764,7 +1796,7 @@ public abstract class AnnotationUtils { */ static List getAttributeAliasNames(Method attribute) { AliasDescriptor descriptor = AliasDescriptor.from(attribute); - return (descriptor != null ? descriptor.getAttributeAliasNames() : Collections. emptyList()); + return (descriptor != null ? descriptor.getAttributeAliasNames() : Collections.emptyList()); } /** diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java index e79d19145d5..1e8561afbb0 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java @@ -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. @@ -64,7 +64,7 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib public void visitEnd() { super.visitEnd(); - Class annotationClass = this.attributes.annotationType(); + Class annotationClass = this.attributes.annotationType(); if (annotationClass != null) { List attributeList = this.attributesMap.get(this.annotationType); if (attributeList == null) { @@ -73,20 +73,22 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib else { attributeList.add(0, this.attributes); } - Set visited = new LinkedHashSet<>(); - Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass); - if (!ObjectUtils.isEmpty(metaAnnotations)) { - for (Annotation metaAnnotation : metaAnnotations) { - if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) { - recursivelyCollectMetaAnnotations(visited, metaAnnotation); + if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationClass.getName())) { + Set visited = new LinkedHashSet<>(); + Annotation[] metaAnnotations = AnnotationUtils.getAnnotations(annotationClass); + if (!ObjectUtils.isEmpty(metaAnnotations)) { + for (Annotation metaAnnotation : metaAnnotations) { + if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) { + recursivelyCollectMetaAnnotations(visited, metaAnnotation); + } } } + Set metaAnnotationTypeNames = new LinkedHashSet<>(visited.size()); + for (Annotation ann : visited) { + metaAnnotationTypeNames.add(ann.annotationType().getName()); + } + this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames); } - Set metaAnnotationTypeNames = new LinkedHashSet<>(visited.size()); - for (Annotation ann : visited) { - metaAnnotationTypeNames.add(ann.annotationType().getName()); - } - this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames); } }