Skip to content

Commit b70c5d1

Browse files
committed
Normalized AnnotationAttributesReadingVisitor class layout and improved diagnostics through delegating to AnnotationUtils
Issue: SPR-12387
1 parent 1e9ab53 commit b70c5d1

6 files changed

+312
-220
lines changed

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

+18-1
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,27 @@ public static <T extends Annotation> T getAnnotation(AnnotatedElement annotatedE
128128
}
129129
}
130130

131+
/**
132+
* Get all {@link Annotation Annotations} from the supplied Method, Constructor or Field.
133+
* @param annotatedElement the Method, Constructor or Field to retrieve annotations from
134+
* @return the annotations found
135+
* @since 4.0.8
136+
*/
137+
public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
138+
try {
139+
return annotatedElement.getAnnotations();
140+
}
141+
catch (Exception ex) {
142+
// Assuming nested Class values not resolvable within annotation attributes...
143+
logIntrospectionFailure(annotatedElement, ex);
144+
return null;
145+
}
146+
}
147+
131148
/**
132149
* Get all {@link Annotation Annotations} from the supplied {@link Method}.
133150
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
134-
* @param method the method to look for annotations on
151+
* @param method the Method to retrieve annotations from
135152
* @return the annotations found
136153
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
137154
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.core.type.classreading;
18+
19+
import java.lang.reflect.Field;
20+
21+
import org.apache.commons.logging.Log;
22+
import org.apache.commons.logging.LogFactory;
23+
24+
import org.springframework.asm.AnnotationVisitor;
25+
import org.springframework.asm.SpringAsmInfo;
26+
import org.springframework.asm.Type;
27+
import org.springframework.core.annotation.AnnotationAttributes;
28+
import org.springframework.util.ReflectionUtils;
29+
30+
/**
31+
* @author Chris Beams
32+
* @author Juergen Hoeller
33+
* @author Phillip Webb
34+
* @author Sam Brannen
35+
* @since 3.1.1
36+
*/
37+
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
38+
39+
protected final Log logger = LogFactory.getLog(getClass());
40+
41+
protected final AnnotationAttributes attributes;
42+
43+
protected final ClassLoader classLoader;
44+
45+
46+
public AbstractRecursiveAnnotationVisitor(ClassLoader classLoader, AnnotationAttributes attributes) {
47+
super(SpringAsmInfo.ASM_VERSION);
48+
this.classLoader = classLoader;
49+
this.attributes = attributes;
50+
}
51+
52+
53+
@Override
54+
public void visit(String attributeName, Object attributeValue) {
55+
this.attributes.put(attributeName, attributeValue);
56+
}
57+
58+
@Override
59+
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
60+
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
61+
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
62+
this.attributes.put(attributeName, nestedAttributes);
63+
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
64+
}
65+
66+
@Override
67+
public AnnotationVisitor visitArray(String attributeName) {
68+
return new RecursiveAnnotationArrayVisitor(attributeName, this.attributes, this.classLoader);
69+
}
70+
71+
@Override
72+
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) {
73+
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue);
74+
visit(attributeName, newValue);
75+
}
76+
77+
protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) {
78+
Object valueToUse = attributeValue;
79+
try {
80+
Class<?> enumType = this.classLoader.loadClass(Type.getType(asmTypeDescriptor).getClassName());
81+
Field enumConstant = ReflectionUtils.findField(enumType, attributeValue);
82+
if (enumConstant != null) {
83+
valueToUse = enumConstant.get(null);
84+
}
85+
}
86+
catch (ClassNotFoundException ex) {
87+
logger.debug("Failed to classload enum type while reading annotation metadata", ex);
88+
}
89+
catch (IllegalAccessException ex) {
90+
logger.warn("Could not access enum value while reading annotation metadata", ex);
91+
}
92+
return valueToUse;
93+
}
94+
95+
}

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java

+3-197
Original file line numberDiff line numberDiff line change
@@ -17,211 +17,15 @@
1717
package org.springframework.core.type.classreading;
1818

1919
import java.lang.annotation.Annotation;
20-
import java.lang.reflect.Array;
21-
import java.lang.reflect.Field;
22-
import java.lang.reflect.Method;
2320
import java.lang.reflect.Modifier;
24-
import java.util.ArrayList;
2521
import java.util.LinkedHashSet;
2622
import java.util.List;
2723
import java.util.Map;
2824
import java.util.Set;
2925

30-
import org.apache.commons.logging.Log;
31-
import org.apache.commons.logging.LogFactory;
32-
33-
import org.springframework.asm.AnnotationVisitor;
34-
import org.springframework.asm.SpringAsmInfo;
35-
import org.springframework.asm.Type;
3626
import org.springframework.core.annotation.AnnotationAttributes;
3727
import org.springframework.core.annotation.AnnotationUtils;
3828
import org.springframework.util.MultiValueMap;
39-
import org.springframework.util.ObjectUtils;
40-
import org.springframework.util.ReflectionUtils;
41-
42-
/**
43-
* @author Chris Beams
44-
* @author Juergen Hoeller
45-
* @author Phillip Webb
46-
* @author Sam Brannen
47-
* @since 3.1.1
48-
*/
49-
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
50-
51-
protected final Log logger = LogFactory.getLog(getClass());
52-
53-
protected final AnnotationAttributes attributes;
54-
55-
protected final ClassLoader classLoader;
56-
57-
public AbstractRecursiveAnnotationVisitor(ClassLoader classLoader, AnnotationAttributes attributes) {
58-
super(SpringAsmInfo.ASM_VERSION);
59-
this.classLoader = classLoader;
60-
this.attributes = attributes;
61-
}
62-
63-
@Override
64-
public void visit(String attributeName, Object attributeValue) {
65-
this.attributes.put(attributeName, attributeValue);
66-
}
67-
68-
@Override
69-
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
70-
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
71-
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
72-
this.attributes.put(attributeName, nestedAttributes);
73-
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
74-
}
75-
76-
@Override
77-
public AnnotationVisitor visitArray(String attributeName) {
78-
return new RecursiveAnnotationArrayVisitor(attributeName, this.attributes, this.classLoader);
79-
}
80-
81-
@Override
82-
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) {
83-
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue);
84-
visit(attributeName, newValue);
85-
}
86-
87-
protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) {
88-
Object valueToUse = attributeValue;
89-
try {
90-
Class<?> enumType = this.classLoader.loadClass(Type.getType(asmTypeDescriptor).getClassName());
91-
Field enumConstant = ReflectionUtils.findField(enumType, attributeValue);
92-
if (enumConstant != null) {
93-
valueToUse = enumConstant.get(null);
94-
}
95-
}
96-
catch (ClassNotFoundException ex) {
97-
logger.debug("Failed to classload enum type while reading annotation metadata", ex);
98-
}
99-
catch (IllegalAccessException ex) {
100-
logger.warn("Could not access enum value while reading annotation metadata", ex);
101-
}
102-
return valueToUse;
103-
}
104-
}
105-
106-
107-
/**
108-
* @author Chris Beams
109-
* @author Juergen Hoeller
110-
* @since 3.1.1
111-
*/
112-
final class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationVisitor {
113-
114-
private final String attributeName;
115-
116-
private final List<AnnotationAttributes> allNestedAttributes = new ArrayList<AnnotationAttributes>();
117-
118-
public RecursiveAnnotationArrayVisitor(
119-
String attributeName, AnnotationAttributes attributes, ClassLoader classLoader) {
120-
super(classLoader, attributes);
121-
this.attributeName = attributeName;
122-
}
123-
124-
@Override
125-
public void visit(String attributeName, Object attributeValue) {
126-
Object newValue = attributeValue;
127-
Object existingValue = this.attributes.get(this.attributeName);
128-
if (existingValue != null) {
129-
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
130-
}
131-
else {
132-
Class<?> arrayClass = newValue.getClass();
133-
if (Enum.class.isAssignableFrom(arrayClass)) {
134-
while (arrayClass.getSuperclass() != null && !arrayClass.isEnum()) {
135-
arrayClass = arrayClass.getSuperclass();
136-
}
137-
}
138-
Object[] newArray = (Object[]) Array.newInstance(arrayClass, 1);
139-
newArray[0] = newValue;
140-
newValue = newArray;
141-
}
142-
this.attributes.put(this.attributeName, newValue);
143-
}
144-
145-
@Override
146-
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) {
147-
String annotationType = Type.getType(asmTypeDescriptor).getClassName();
148-
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
149-
this.allNestedAttributes.add(nestedAttributes);
150-
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader);
151-
}
152-
153-
@Override
154-
public void visitEnd() {
155-
if (!this.allNestedAttributes.isEmpty()) {
156-
this.attributes.put(this.attributeName,
157-
this.allNestedAttributes.toArray(new AnnotationAttributes[this.allNestedAttributes.size()]));
158-
}
159-
}
160-
}
161-
162-
163-
/**
164-
* @author Chris Beams
165-
* @author Juergen Hoeller
166-
* @since 3.1.1
167-
*/
168-
class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVisitor {
169-
170-
private final String annotationType;
171-
172-
public RecursiveAnnotationAttributesVisitor(String annotationType, AnnotationAttributes attributes,
173-
ClassLoader classLoader) {
174-
super(classLoader, attributes);
175-
this.annotationType = annotationType;
176-
}
177-
178-
@Override
179-
public final void visitEnd() {
180-
try {
181-
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
182-
doVisitEnd(annotationClass);
183-
}
184-
catch (ClassNotFoundException ex) {
185-
logger.debug("Failed to class-load type while reading annotation metadata. " +
186-
"This is a non-fatal error, but certain annotation metadata may be unavailable.", ex);
187-
}
188-
}
189-
190-
protected void doVisitEnd(Class<?> annotationClass) {
191-
registerDefaultValues(annotationClass);
192-
}
193-
194-
private void registerDefaultValues(Class<?> annotationClass) {
195-
// Only do further scanning for public annotations; we'd run into
196-
// IllegalAccessExceptions otherwise, and we don't want to mess with
197-
// accessibility in a SecurityManager environment.
198-
if (Modifier.isPublic(annotationClass.getModifiers())) {
199-
// Check declared default values of attributes in the annotation type.
200-
Method[] annotationAttributes = annotationClass.getMethods();
201-
for (Method annotationAttribute : annotationAttributes) {
202-
String attributeName = annotationAttribute.getName();
203-
Object defaultValue = annotationAttribute.getDefaultValue();
204-
if (defaultValue != null && !this.attributes.containsKey(attributeName)) {
205-
if (defaultValue instanceof Annotation) {
206-
defaultValue = AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(
207-
(Annotation) defaultValue, false, true));
208-
}
209-
else if (defaultValue instanceof Annotation[]) {
210-
Annotation[] realAnnotations = (Annotation[]) defaultValue;
211-
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
212-
for (int i = 0; i < realAnnotations.length; i++) {
213-
mappedAnnotations[i] = AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(
214-
realAnnotations[i], false, true));
215-
}
216-
defaultValue = mappedAnnotations;
217-
}
218-
this.attributes.put(attributeName, defaultValue);
219-
}
220-
}
221-
}
222-
}
223-
}
224-
22529

22630
/**
22731
* ASM visitor which looks for the annotations defined on a class or method, including
@@ -245,6 +49,7 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
24549

24650
private final Map<String, Set<String>> metaAnnotationMap;
24751

52+
24853
public AnnotationAttributesReadingVisitor(String annotationType,
24954
MultiValueMap<String, AnnotationAttributes> attributesMap, Map<String, Set<String>> metaAnnotationMap,
25055
ClassLoader classLoader) {
@@ -255,6 +60,7 @@ public AnnotationAttributesReadingVisitor(String annotationType,
25560
this.metaAnnotationMap = metaAnnotationMap;
25661
}
25762

63+
25864
@Override
25965
public void doVisitEnd(Class<?> annotationClass) {
26066
super.doVisitEnd(annotationClass);
@@ -266,7 +72,7 @@ public void doVisitEnd(Class<?> annotationClass) {
26672
attributes.add(0, this.attributes);
26773
}
26874
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
269-
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
75+
for (Annotation metaAnnotation : AnnotationUtils.getAnnotations(annotationClass)) {
27076
if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) {
27177
recursivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation);
27278
}

0 commit comments

Comments
 (0)