Polish ASM-based annotation processing
- AnnotationAttributesReadingVisitor no longer processes annotations from the java.lang.annotation package. - Simplified logic in AnnotationReadingVisitorUtils getMergedAnnotationAttributes(). Issue: SPR-11574
This commit is contained in:
parent
90e3dbb0f5
commit
796af90ba7
|
@ -130,8 +130,8 @@ final class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationV
|
|||
}
|
||||
else {
|
||||
Class<?> arrayClass = newValue.getClass();
|
||||
if(Enum.class.isAssignableFrom(arrayClass)) {
|
||||
while(arrayClass.getSuperclass() != null && !arrayClass.isEnum()) {
|
||||
if (Enum.class.isAssignableFrom(arrayClass)) {
|
||||
while (arrayClass.getSuperclass() != null && !arrayClass.isEnum()) {
|
||||
arrayClass = arrayClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
@ -153,8 +153,8 @@ final class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationV
|
|||
@Override
|
||||
public void visitEnd() {
|
||||
if (!this.allNestedAttributes.isEmpty()) {
|
||||
this.attributes.put(this.attributeName, this.allNestedAttributes.toArray(
|
||||
new AnnotationAttributes[this.allNestedAttributes.size()]));
|
||||
this.attributes.put(this.attributeName,
|
||||
this.allNestedAttributes.toArray(new AnnotationAttributes[this.allNestedAttributes.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,8 +169,9 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
|
||||
private final String annotationType;
|
||||
|
||||
public RecursiveAnnotationAttributesVisitor(
|
||||
String annotationType, AnnotationAttributes attributes, ClassLoader classLoader) {
|
||||
|
||||
public RecursiveAnnotationAttributesVisitor(String annotationType, AnnotationAttributes attributes,
|
||||
ClassLoader classLoader) {
|
||||
super(classLoader, attributes);
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
@ -182,8 +183,8 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
doVisitEnd(annotationClass);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
this.logger.debug("Failed to class-load type while reading annotation metadata. " +
|
||||
"This is a non-fatal error, but certain annotation metadata may be unavailable.", ex);
|
||||
this.logger.debug("Failed to class-load type while reading annotation metadata. "
|
||||
+ "This is a non-fatal error, but certain annotation metadata may be unavailable.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,8 +193,9 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
}
|
||||
|
||||
private void registerDefaultValues(Class<?> annotationClass) {
|
||||
// Only do further scanning for public annotations; we'd run into IllegalAccessExceptions
|
||||
// otherwise, and don't want to mess with accessibility in a SecurityManager environment.
|
||||
// Only do further scanning for public annotations; we'd run into
|
||||
// IllegalAccessExceptions otherwise, and we don't want to mess with
|
||||
// accessibility in a SecurityManager environment.
|
||||
if (Modifier.isPublic(annotationClass.getModifiers())) {
|
||||
// Check declared default values of attributes in the annotation type.
|
||||
Method[] annotationAttributes = annotationClass.getMethods();
|
||||
|
@ -202,15 +204,15 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
Object defaultValue = annotationAttribute.getDefaultValue();
|
||||
if (defaultValue != null && !this.attributes.containsKey(attributeName)) {
|
||||
if (defaultValue instanceof Annotation) {
|
||||
defaultValue = AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes((Annotation) defaultValue, false, true));
|
||||
defaultValue = AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(
|
||||
(Annotation) defaultValue, false, true));
|
||||
}
|
||||
else if (defaultValue instanceof Annotation[]) {
|
||||
Annotation[] realAnnotations = (Annotation[]) defaultValue;
|
||||
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
|
||||
for (int i = 0; i < realAnnotations.length; i++) {
|
||||
mappedAnnotations[i] = AnnotationAttributes.fromMap(
|
||||
AnnotationUtils.getAnnotationAttributes(realAnnotations[i], false, true));
|
||||
mappedAnnotations[i] = AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(
|
||||
realAnnotations[i], false, true));
|
||||
}
|
||||
defaultValue = mappedAnnotations;
|
||||
}
|
||||
|
@ -233,6 +235,7 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttributesVisitor {
|
||||
|
@ -244,9 +247,9 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
|
|||
private final Map<String, Set<String>> metaAnnotationMap;
|
||||
|
||||
|
||||
public AnnotationAttributesReadingVisitor(
|
||||
String annotationType, MultiValueMap<String, AnnotationAttributes> attributesMap,
|
||||
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
|
||||
public AnnotationAttributesReadingVisitor(String annotationType,
|
||||
MultiValueMap<String, AnnotationAttributes> attributesMap, Map<String, Set<String>> metaAnnotationMap,
|
||||
ClassLoader classLoader) {
|
||||
|
||||
super(annotationType, new AnnotationAttributes(), classLoader);
|
||||
this.annotationType = annotationType;
|
||||
|
@ -267,7 +270,9 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
|
|||
}
|
||||
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
|
||||
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
|
||||
recursivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation);
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(metaAnnotation)) {
|
||||
recursivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation);
|
||||
}
|
||||
}
|
||||
if (this.metaAnnotationMap != null) {
|
||||
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
|
||||
|
@ -275,16 +280,18 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
|
|||
}
|
||||
|
||||
private void recursivelyCollectMetaAnnotations(Set<String> visited, Annotation annotation) {
|
||||
if (visited.add(annotation.annotationType().getName())) {
|
||||
// Only do further scanning for public annotations; we'd run into IllegalAccessExceptions
|
||||
// otherwise, and don't want to mess with accessibility in a SecurityManager environment.
|
||||
String annotationName = annotation.annotationType().getName();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) && visited.add(annotationName)) {
|
||||
// Only do further scanning for public annotations; we'd run into
|
||||
// IllegalAccessExceptions otherwise, and we don't want to mess with
|
||||
// accessibility in a SecurityManager environment.
|
||||
if (Modifier.isPublic(annotation.annotationType().getModifiers())) {
|
||||
this.attributesMap.add(annotation.annotationType().getName(),
|
||||
AnnotationUtils.getAnnotationAttributes(annotation, false, true));
|
||||
this.attributesMap.add(annotationName, AnnotationUtils.getAnnotationAttributes(annotation, false, true));
|
||||
for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) {
|
||||
recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,11 +53,11 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>(4);
|
||||
|
||||
/**
|
||||
* Declared as a {@link LinkedMultiValueMap} instead of {@link MultiValueMap}
|
||||
* in order to ensure that ordering of entries is enforced.
|
||||
* Declared as a {@link LinkedMultiValueMap} instead of a {@link MultiValueMap}
|
||||
* to ensure that the hierarchical ordering of the entries is preserved.
|
||||
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes(LinkedMultiValueMap, String)
|
||||
*/
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributeMap = new LinkedMultiValueMap<String, AnnotationAttributes>(
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(
|
||||
4);
|
||||
|
||||
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
|
||||
|
@ -77,7 +77,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
|
||||
String className = Type.getType(desc).getClassName();
|
||||
this.annotationSet.add(className);
|
||||
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, this.metaAnnotationMap, this.classLoader);
|
||||
return new AnnotationAttributesReadingVisitor(className, this.attributesMap, this.metaAnnotationMap, this.classLoader);
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,7 +109,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
|
||||
@Override
|
||||
public boolean isAnnotated(String annotationType) {
|
||||
return this.attributeMap.containsKey(annotationType);
|
||||
return this.attributesMap.containsKey(annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,7 +119,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
|
||||
@Override
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributeMap,
|
||||
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributesMap,
|
||||
annotationType);
|
||||
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
@Override
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>();
|
||||
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
|
||||
List<AnnotationAttributes> attributes = this.attributesMap.get(annotationType);
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.core.type.classreading;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -26,7 +27,7 @@ import org.springframework.asm.Type;
|
|||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
import static org.springframework.core.annotation.AnnotationUtils.VALUE;
|
||||
|
||||
/**
|
||||
* Internal utility class used when reading annotations.
|
||||
|
@ -98,22 +99,22 @@ abstract class AnnotationReadingVisitorUtils {
|
|||
|
||||
/**
|
||||
* Retrieve the merged attributes of the annotation of the given type, if any,
|
||||
* from the supplied {@code attributeMap}.
|
||||
* from the supplied {@code attributesMap}.
|
||||
* <p>Annotation attribute values appearing <em>lower</em> in the annotation
|
||||
* hierarchy (i.e., closer to the declaring class) will override those
|
||||
* defined <em>higher</em> in the annotation hierarchy.
|
||||
* @param attributeMap the map of annotation attribute lists, keyed by
|
||||
* annotation type
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param attributesMap the map of annotation attribute lists, keyed by
|
||||
* annotation type name
|
||||
* @param annotationType the name of the annotation type to look for
|
||||
* @return the merged annotation attributes; or {@code null} if no matching
|
||||
* annotation is present in the {@code attributeMap}
|
||||
* annotation is present in the {@code attributesMap}
|
||||
* @since 4.0.3
|
||||
*/
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
LinkedMultiValueMap<String, AnnotationAttributes> attributeMap, String annotationType) {
|
||||
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap, String annotationType) {
|
||||
|
||||
// Get the unmerged list of attributes for the target annotation.
|
||||
List<AnnotationAttributes> attributesList = attributeMap.get(annotationType);
|
||||
List<AnnotationAttributes> attributesList = attributesMap.get(annotationType);
|
||||
if (attributesList == null || attributesList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -121,28 +122,27 @@ abstract class AnnotationReadingVisitorUtils {
|
|||
// To start with, we populate the results with all attribute values from the
|
||||
// target annotation.
|
||||
AnnotationAttributes results = attributesList.get(0);
|
||||
Set<String> supportedAttributeNames = results.keySet();
|
||||
|
||||
Set<String> overridableAttributeNames = new HashSet<String>(results.keySet());
|
||||
overridableAttributeNames.remove(VALUE);
|
||||
|
||||
// Since the map is a LinkedMultiValueMap, we depend on the ordering of
|
||||
// elements in the map and reverse the order of the keys in order to traverse
|
||||
// "down" the meta-annotation hierarchy.
|
||||
List<String> annotationTypes = new ArrayList<String>(attributeMap.keySet());
|
||||
// "down" the annotation hierarchy.
|
||||
List<String> annotationTypes = new ArrayList<String>(attributesMap.keySet());
|
||||
Collections.reverse(annotationTypes);
|
||||
|
||||
for (String currentAnnotationType : annotationTypes) {
|
||||
if (!currentAnnotationType.startsWith("java.lang.annotation")) {
|
||||
for (String attributeName : supportedAttributeNames) {
|
||||
if (!VALUE.equals(attributeName)) {
|
||||
List<AnnotationAttributes> currentAttributes = attributeMap.get(currentAnnotationType);
|
||||
if (currentAttributes != null && !currentAttributes.isEmpty()) {
|
||||
Object value = currentAttributes.get(0).get(attributeName);
|
||||
if (value != null) {
|
||||
// Overwrite value from target annotation with the value
|
||||
// from an attribute of the same name found lower in the
|
||||
// meta-annotation hierarchy.
|
||||
results.put(attributeName, value);
|
||||
}
|
||||
}
|
||||
List<AnnotationAttributes> currentAttributesList = attributesMap.get(currentAnnotationType);
|
||||
if (currentAttributesList != null && !currentAttributesList.isEmpty()) {
|
||||
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
|
||||
for (String overridableAttributeName : overridableAttributeNames) {
|
||||
Object value = currentAttributes.get(overridableAttributeName);
|
||||
if (value != null) {
|
||||
// Store the value, potentially overriding a value from an
|
||||
// attribute of the same name found higher in the annotation
|
||||
// hierarchy.
|
||||
results.put(overridableAttributeName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue