@Configuration parsing fully relies on Spring's MetadataReader abstraction now

This commit is contained in:
Juergen Hoeller
2009-04-24 11:16:46 +00:00
parent 37e1333a41
commit b5d21108da
30 changed files with 819 additions and 1944 deletions

View File

@@ -231,19 +231,46 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the given annotation's attributes as a Map.
* Retrieve the given annotation's attributes as a Map,
* preserving all attribute types as-is.
* @param annotation the annotation to retrieve the attributes for
* @return the Map of annotation attributes, with attribute names as keys
* and corresponding attribute values as values
*/
public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
return getAnnotationAttributes(annotation, false);
}
/**
* Retrieve the given annotation's attributes as a Map.
* @param annotation the annotation to retrieve the attributes for
* @param filterClasses whether to turn Class references into Strings
* (for compatibility with {@link org.springframework.core.type.AnnotationMetadata}
* or to preserve them as Class references
* @return the Map of annotation attributes, with attribute names as keys
* and corresponding attribute values as values
*/
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean filterClasses) {
Map<String, Object> attrs = new HashMap<String, Object>();
Method[] methods = annotation.annotationType().getDeclaredMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
for (Method method : methods) {
if (method.getParameterTypes().length == 0 && method.getReturnType() != void.class) {
try {
attrs.put(method.getName(), method.invoke(annotation));
Object value = method.invoke(annotation);
if (filterClasses) {
if (value instanceof Class) {
value = ((Class) value).getName();
}
else if (value instanceof Class[]) {
Class[] clazzArray = (Class[]) value;
String[] newValue = new String[clazzArray.length];
for (int i = 0; i < clazzArray.length; i++) {
newValue[i] = clazzArray[i].getName();
}
value = newValue;
}
}
attrs.put(method.getName(), value);
}
catch (Exception ex) {
throw new IllegalStateException("Could not obtain annotation attribute values", ex);

View File

@@ -45,9 +45,20 @@ public interface AnnotationMetadata extends ClassMetadata {
*/
boolean hasAnnotation(String annotationType);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying class).
* @param annotationType the annotation type to look for
* @return a Map of attributes, with the attribute name as key (e.g. "value")
* and the defined attribute value as Map value. This return value will be
* <code>null</code> if no matching annotation is defined.
*/
Map<String, Object> getAnnotationAttributes(String annotationType);
/**
* Return the names of all meta-annotation types defined on the
* given annotation type of the underlying class.
* @param annotationType the meta-annotation type to look for
* @return the meta-annotation type names
*/
Set<String> getMetaAnnotationTypes(String annotationType);
@@ -61,26 +72,20 @@ public interface AnnotationMetadata extends ClassMetadata {
boolean hasMetaAnnotation(String metaAnnotationType);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying class).
* @param annotationType the annotation type to look for
* @return a Map of attributes, with the attribute name as key
* (e.g. "value") and the defined attribute value as Map value.
* This return value will be <code>null</code> if no matching
* annotation is defined.
* Retrieve the method metadata for all methods that are annotated
* with at least one annotation type.
* @return a Set of {@link MethodMetadata} for methods that have annotations.
* The return value will be an empty set if no annotated methods are found.
*/
Map<String, Object> getAnnotationAttributes(String annotationType);
// TODO return null would be more consistent with other methods if no match is found
Set<MethodMetadata> getAnnotatedMethods();
/**
* Retrieve the method meta-data for all methods that have the
* Retrieve the method metadata for all methods that have the
* given annotation type.
* @param annotationType the annotation type to look for
* @return a Set of (@link MethodMetadata) for methods that
* have a matching annotation. The return value will be an
* empty set if no methods match the annotation type.
* @return a Set of {@link MethodMetadata} for methods that have a matching
* annotation. The return value will be an empty set if no methods match
* the annotation type.
*/
Set<MethodMetadata> getAnnotatedMethods(String annotationType);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -49,6 +49,11 @@ public interface ClassMetadata {
*/
boolean isConcrete();
/**
* Return whether the underlying class is marked as 'final'.
*/
boolean isFinal();
/**
* Determine whether the underlying class is independent,
* i.e. whether it is a top-level class or a nested class

View File

@@ -20,41 +20,60 @@ import java.util.Map;
import java.util.Set;
/**
* Interface that defines abstract access to the annotations of a specific
* class, in a form that does not require that class to be loaded yet.
*
* @author Mark Pollack
* @author Juergen Hoeller
* @since 3.0
* @see StandardMethodMetadata
* @see AnnotationMetadata#getAnnotatedMethods
*/
public interface MethodMetadata {
int getModifiers();
boolean isStatic();
/**
* Return the name of the method.
*/
String getMethodName();
//TODO does the method return type have a generic wildcard or generic type parameters?
// annotation metadata
Set<String> getAnnotationTypes();
boolean hasAnnotation(String annotationType);
Map<String, Object> getAnnotationAttributes(String annotationType);
/**
* Determine whether the underlying class has an annotation that
* is itself annotated with the meta-annotation of the given type.
* @param metaAnnotationType the meta-annotation type to look for
* @return whether a matching meta-annotation is defined
*/
boolean hasMetaAnnotation(String metaAnnotationType);
/**
* Return the names of all meta-annotation types defined on the
* given annotation type of the underlying class.
* @return the meta-annotation type names
*/
Set<String> getMetaAnnotationTypes(String annotationType);
Set<String> getAnnotationTypesWithMetaAnnotation(String qualifierClassName);
/**
* Return whether the underlying method is declared as 'static'.
*/
boolean isStatic();
/**
* Return whether the underlying method is marked as 'final'.
*/
boolean isFinal();
/**
* Return whether the underlying method is overridable,
* i.e. not marked as static, final or private.
*/
boolean isOverridable();
/**
* Return the names of all annotation types defined on the underlying method.
* @return the annotation type names, or an empty Set if none found
*/
Set<String> getAnnotationTypes();
/**
* Determine whether the underlying method has an annotation of the given
* type defined.
* @param annotationType the annotation type to look for
* @return whether a matching annotation is defined
*/
boolean hasAnnotation(String annotationType);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying method).
* @param annotationType the annotation type to look for
* @return a Map of attributes, with the attribute name as key (e.g. "value")
* and the defined attribute value as Map value. This return value will be
* <code>null</code> if no matching annotation is defined.
*/
Map<String, Object> getAnnotationAttributes(String annotationType);
}

View File

@@ -35,6 +35,10 @@ import org.springframework.core.annotation.AnnotationUtils;
*/
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
/**
* Create a new StandardAnnotationMetadata wrapper for the given Class.
* @param introspectedClass the Class to introspect
*/
public StandardAnnotationMetadata(Class introspectedClass) {
super(introspectedClass);
}
@@ -59,6 +63,16 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(ann, true);
}
}
return null;
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
@@ -87,25 +101,25 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(ann);
public Set<MethodMetadata> getAnnotatedMethods() {
Method[] methods = getIntrospectedClass().getDeclaredMethods();
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (Method method : methods) {
if (method.getAnnotations().length > 0) {
annotatedMethods.add(new StandardMethodMetadata(method));
}
}
return null;
return annotatedMethods;
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Method[] methods = getIntrospectedClass().getMethods();
Method[] methods = getIntrospectedClass().getDeclaredMethods();
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (Method method : methods) {
Annotation[] methodAnnotations = method.getAnnotations();
for (Annotation ann : methodAnnotations) {
if (ann.annotationType().getName().equals(annotationType)) {
MethodMetadata mm = new StandardMethodMetadata(method);
annotatedMethods.add(mm);
annotatedMethods.add(new StandardMethodMetadata(method));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -18,6 +18,8 @@ package org.springframework.core.type;
import java.lang.reflect.Modifier;
import org.springframework.util.Assert;
/**
* {@link ClassMetadata} implementation that uses standard reflection
* to introspect a given <code>Class</code>.
@@ -30,57 +32,69 @@ public class StandardClassMetadata implements ClassMetadata {
private final Class introspectedClass;
/**
* Create a new StandardClassMetadata wrapper for the given Class.
* @param introspectedClass the Class to introspect
*/
public StandardClassMetadata(Class introspectedClass) {
Assert.notNull(introspectedClass, "Class must not be null");
this.introspectedClass = introspectedClass;
}
/**
* Return the underlying Class.
*/
public final Class getIntrospectedClass() {
return this.introspectedClass;
}
public String getClassName() {
return getIntrospectedClass().getName();
return this.introspectedClass.getName();
}
public boolean isInterface() {
return getIntrospectedClass().isInterface();
return this.introspectedClass.isInterface();
}
public boolean isAbstract() {
return Modifier.isAbstract(getIntrospectedClass().getModifiers());
return Modifier.isAbstract(this.introspectedClass.getModifiers());
}
public boolean isConcrete() {
return !(isInterface() || isAbstract());
}
public boolean isFinal() {
return Modifier.isFinal(this.introspectedClass.getModifiers());
}
public boolean isIndependent() {
return (!hasEnclosingClass() ||
(getIntrospectedClass().getDeclaringClass() != null &&
Modifier.isStatic(getIntrospectedClass().getModifiers())));
(this.introspectedClass.getDeclaringClass() != null &&
Modifier.isStatic(this.introspectedClass.getModifiers())));
}
public boolean hasEnclosingClass() {
return (getIntrospectedClass().getEnclosingClass() != null);
return (this.introspectedClass.getEnclosingClass() != null);
}
public String getEnclosingClassName() {
Class enclosingClass = getIntrospectedClass().getEnclosingClass();
Class enclosingClass = this.introspectedClass.getEnclosingClass();
return (enclosingClass != null ? enclosingClass.getName() : null);
}
public boolean hasSuperClass() {
return (getIntrospectedClass().getSuperclass() != null);
return (this.introspectedClass.getSuperclass() != null);
}
public String getSuperClassName() {
Class superClass = getIntrospectedClass().getSuperclass();
Class superClass = this.introspectedClass.getSuperclass();
return (superClass != null ? superClass.getName() : null);
}
public String[] getInterfaceNames() {
Class[] ifcs = getIntrospectedClass().getInterfaces();
Class[] ifcs = this.introspectedClass.getInterfaces();
String[] ifcNames = new String[ifcs.length];
for (int i = 0; i < ifcs.length; i++) {
ifcNames[i] = ifcs[i].getName();

View File

@@ -17,7 +17,6 @@
package org.springframework.core.type;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
@@ -28,52 +27,62 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
/**
* {@link MethodMetadata} implementation that uses standard reflection
* to introspect a given <code>Method</code>.
*
* @author Mark Pollack
* @author Juergen Hoeller
* @since 3.0
*/
public class StandardMethodMetadata implements MethodMetadata {
private final Method introspectedMethod;
public StandardMethodMetadata(Method method) {
Assert.notNull(method, "Method must not be null");
introspectedMethod = method;
/**
* Create a new StandardMethodMetadata wrapper for the given Method.
* @param introspectedMethod the Method to introspect
*/
public StandardMethodMetadata(Method introspectedMethod) {
Assert.notNull(introspectedMethod, "Method must not be null");
this.introspectedMethod = introspectedMethod;
}
/**
* Return the underlying Method.
*/
public final Method getIntrospectedMethod() {
return this.introspectedMethod;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(ann);
}
}
return null;
public String getMethodName() {
return this.introspectedMethod.getName();
}
public boolean isStatic() {
return Modifier.isStatic(this.introspectedMethod.getModifiers());
}
public boolean isFinal() {
return Modifier.isFinal(this.introspectedMethod.getModifiers());
}
public boolean isOverridable() {
return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers()));
}
public Set<String> getAnnotationTypes() {
Set<String> types = new HashSet<String>();
Annotation[] anns = getIntrospectedMethod().getAnnotations();
Annotation[] anns = this.introspectedMethod.getAnnotations();
for (Annotation ann : anns) {
types.add(ann.annotationType().getName());
}
return types;
}
public String getMethodName() {
return introspectedMethod.getName();
}
public int getModifiers() {
return introspectedMethod.getModifiers();
}
public boolean hasAnnotation(String annotationType) {
Annotation[] anns = getIntrospectedMethod().getAnnotations();
Annotation[] anns = this.introspectedMethod.getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return true;
@@ -82,44 +91,14 @@ public class StandardMethodMetadata implements MethodMetadata {
return false;
}
public boolean isStatic() {
return Modifier.isStatic(getIntrospectedMethod().getModifiers());
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
Annotation[] anns = getIntrospectedMethod().getAnnotations();
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = this.introspectedMethod.getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
Set<String> types = new HashSet<String>();
Annotation[] metaAnns = ann.annotationType().getAnnotations();
for (Annotation meta : metaAnns) {
types.add(meta.annotationType().getName());
}
return types;
return AnnotationUtils.getAnnotationAttributes(ann, true);
}
}
return null;
}
public boolean hasMetaAnnotation(String metaAnnotationType) {
//TODO can refactor into shared (utility) method with StandardAnnotationMetadata
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (Annotation ann : anns) {
Annotation[] metaAnns = ann.annotationType().getAnnotations();
for (Annotation meta : metaAnns) {
if (meta.annotationType().getName().equals(metaAnnotationType)) {
return true;
}
}
}
return false;
}
public Set<String> getAnnotationTypesWithMetaAnnotation(String qualifierClassName) {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,150 @@
/*
* Copyright 2002-2009 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.type.classreading;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* ASM visitor which looks for the annotations defined on a class or method.
*
* @author Juergen Hoeller
* @since 3.0
*/
final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
private final String annotationType;
private final Map<String, Map<String, Object>> annotationMap;
private final Map<String, Set<String>> metaAnnotationMap;
private final ClassLoader classLoader;
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
public AnnotationAttributesReadingVisitor(
String annotationType, Map<String, Map<String, Object>> attributesMap,
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
this.annotationType = annotationType;
this.annotationMap = attributesMap;
this.metaAnnotationMap = metaAnnotationMap;
this.classLoader = classLoader;
}
public void visit(String name, Object value) {
Object valueToUse = value;
if (valueToUse instanceof Type) {
valueToUse = ((Type) value).getClassName();
}
this.attributes.put(name, valueToUse);
}
public void visitEnum(String name, String desc, String value) {
Object valueToUse = value;
try {
Class<?> enumType = this.classLoader.loadClass(Type.getType(desc).getClassName());
Field enumConstant = ReflectionUtils.findField(enumType, value);
if (enumConstant != null) {
valueToUse = enumConstant.get(null);
}
}
catch (Exception ex) {
// Class not found - can't resolve class reference in annotation attribute.
}
this.attributes.put(name, valueToUse);
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
return new EmptyVisitor();
}
public AnnotationVisitor visitArray(final String attrName) {
return new AnnotationVisitor() {
public void visit(String name, Object value) {
Object newValue = value;
if (newValue instanceof Type) {
newValue = ((Type) value).getClassName();
}
Object existingValue = attributes.get(attrName);
if (existingValue != null) {
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
}
else {
Object[] newArray = (Object[]) Array.newInstance(newValue.getClass(), 1);
newArray[0] = newValue;
newValue = newArray;
}
attributes.put(attrName, newValue);
}
public void visitEnum(String name, String desc, String value) {
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
return new EmptyVisitor();
}
public AnnotationVisitor visitArray(String name) {
return new EmptyVisitor();
}
public void visitEnd() {
}
};
}
public void visitEnd() {
try {
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
// Check declared default values of attributes in the annotation type.
Method[] annotationAttributes = annotationClass.getMethods();
for (Method annotationAttribute : annotationAttributes) {
String attributeName = annotationAttribute.getName();
Object defaultValue = annotationAttribute.getDefaultValue();
if (defaultValue != null && !this.attributes.containsKey(attributeName)) {
this.attributes.put(attributeName, defaultValue);
}
}
// Register annotations that the annotation type is annotated with.
if (this.metaAnnotationMap != null) {
Annotation[] metaAnnotations = annotationClass.getAnnotations();
Set<String> metaAnnotationTypeNames = new HashSet<String>();
for (Annotation metaAnnotation : metaAnnotations) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
}
this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames);
}
}
catch (ClassNotFoundException ex) {
// Class not found - can't determine meta-annotations.
}
this.annotationMap.put(this.annotationType, this.attributes);
}
}

View File

@@ -16,12 +16,7 @@
package org.springframework.core.type.classreading;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -30,11 +25,8 @@ import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* ASM class visitor which looks for the class name and implemented types as
@@ -45,9 +37,9 @@ import org.springframework.util.ReflectionUtils;
* @author Mark Fisher
* @since 2.5
*/
class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
private final Map<String, Map<String, Object>> attributesMap = new LinkedHashMap<String, Map<String, Object>>();
private final Map<String, Map<String, Object>> annotationMap = new LinkedHashMap<String, Map<String, Object>>();
private final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>();
@@ -63,109 +55,28 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodMetadataReadingVisitor md = new MethodMetadataReadingVisitor(classLoader, name, access);
methodMetadataSet.add(md);
return md;
MethodMetadataReadingVisitor mm = new MethodMetadataReadingVisitor(name, access, this.classLoader);
this.methodMetadataSet.add(mm);
return mm;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
final String className = Type.getType(desc).getClassName();
final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
return new AnnotationVisitor() {
public void visit(String name, Object value) {
// Explicitly defined annotation attribute value.
Object valueToUse = value;
if (value instanceof Type) {
try {
valueToUse = classLoader.loadClass(((Type) value).getClassName());
}
catch (ClassNotFoundException ex) {
// Class not found - can't resolve class reference in annotation attribute.
}
}
attributes.put(name, valueToUse);
}
public void visitEnum(String name, String desc, String value) {
Object valueToUse = value;
try {
Class<?> enumType = classLoader.loadClass(Type.getType(desc).getClassName());
Field enumConstant = ReflectionUtils.findField(enumType, value);
if (enumConstant != null) {
valueToUse = enumConstant.get(null);
}
}
catch (Exception ex) {
// Class not found - can't resolve class reference in annotation attribute.
}
attributes.put(name, valueToUse);
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
return new EmptyVisitor();
}
public AnnotationVisitor visitArray(final String attrName) {
return new AnnotationVisitor() {
public void visit(String name, Object value) {
Object newValue = value;
Object existingValue = attributes.get(attrName);
if (existingValue != null) {
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
}
else {
Object[] newArray = (Object[]) Array.newInstance(newValue.getClass(), 1);
newArray[0] = newValue;
newValue = newArray;
}
attributes.put(attrName, newValue);
}
public void visitEnum(String name, String desc, String value) {
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
return new EmptyVisitor();
}
public AnnotationVisitor visitArray(String name) {
return new EmptyVisitor();
}
public void visitEnd() {
}
};
}
public void visitEnd() {
try {
Class<?> annotationClass = classLoader.loadClass(className);
// Check declared default values of attributes in the annotation type.
Method[] annotationAttributes = annotationClass.getMethods();
for (Method annotationAttribute : annotationAttributes) {
String attributeName = annotationAttribute.getName();
Object defaultValue = annotationAttribute.getDefaultValue();
if (defaultValue != null && !attributes.containsKey(attributeName)) {
attributes.put(attributeName, defaultValue);
}
}
// Register annotations that the annotation type is annotated with.
Annotation[] metaAnnotations = annotationClass.getAnnotations();
Set<String> metaAnnotationTypeNames = new HashSet<String>();
for (Annotation metaAnnotation : metaAnnotations) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
}
metaAnnotationMap.put(className, metaAnnotationTypeNames);
}
catch (ClassNotFoundException ex) {
// Class not found - can't determine meta-annotations.
}
attributesMap.put(className, attributes);
}
};
String className = Type.getType(desc).getClassName();
return new AnnotationAttributesReadingVisitor(className, this.annotationMap, this.metaAnnotationMap, this.classLoader);
}
public Set<String> getAnnotationTypes() {
return this.attributesMap.keySet();
return this.annotationMap.keySet();
}
public boolean hasAnnotation(String annotationType) {
return this.attributesMap.containsKey(annotationType);
return this.annotationMap.containsKey(annotationType);
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.annotationMap.get(annotationType);
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
@@ -182,17 +93,20 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributesMap.get(annotationType);
public Set<MethodMetadata> getAnnotatedMethods() {
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (MethodMetadata method : this.methodMetadataSet) {
if (!method.getAnnotationTypes().isEmpty()) {
annotatedMethods.add(method);
}
}
return annotatedMethods;
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (MethodMetadata method : methodMetadataSet) {
if (method.hasAnnotation(annotationType))
{
for (MethodMetadata method : this.methodMetadataSet) {
if (method.hasAnnotation(annotationType)) {
annotatedMethods.add(method);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@@ -33,7 +33,7 @@ import org.springframework.core.io.ResourceLoader;
*/
public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
private final Map<Resource, SimpleMetadataReader> classReaderCache = new HashMap<Resource, SimpleMetadataReader>();
private final Map<Resource, MetadataReader> classReaderCache = new HashMap<Resource, MetadataReader>();
/**
@@ -62,9 +62,9 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
@Override
public SimpleMetadataReader getMetadataReader(Resource resource) throws IOException {
public MetadataReader getMetadataReader(Resource resource) throws IOException {
synchronized (this.classReaderCache) {
SimpleMetadataReader metadataReader = this.classReaderCache.get(resource);
MetadataReader metadataReader = this.classReaderCache.get(resource);
if (metadataReader == null) {
metadataReader = super.getMetadataReader(resource);
this.classReaderCache.put(resource, metadataReader);

View File

@@ -45,6 +45,8 @@ class ClassMetadataReadingVisitor implements ClassVisitor, ClassMetadata {
private boolean isAbstract;
private boolean isFinal;
private String enclosingClassName;
private boolean independentInnerClass;
@@ -58,6 +60,7 @@ class ClassMetadataReadingVisitor implements ClassVisitor, ClassMetadata {
this.className = ClassUtils.convertResourcePathToClassName(name);
this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0);
this.isFinal = ((access & Opcodes.ACC_FINAL) != 0);
if (supername != null) {
this.superClassName = ClassUtils.convertResourcePathToClassName(supername);
}
@@ -122,6 +125,10 @@ class ClassMetadataReadingVisitor implements ClassVisitor, ClassMetadata {
return !(this.isInterface || this.isAbstract);
}
public boolean isFinal() {
return this.isFinal;
}
public boolean isIndependent() {
return (this.enclosingClassName == null || this.independentInnerClass);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@@ -16,6 +16,7 @@
package org.springframework.core.type.classreading;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
@@ -28,13 +29,19 @@ import org.springframework.core.type.ClassMetadata;
*/
public interface MetadataReader {
/**
* Return the resource reference for the class file.
*/
Resource getResource();
/**
* Read basic class metadata for the underlying class.
*/
ClassMetadata getClassMetadata();
/**
* Read full annotation metadata for the underlying class.
* Read full annotation metadata for the underlying class,
* including metadata for annotated methods.
*/
AnnotationMetadata getAnnotationMetadata();

View File

@@ -16,13 +16,7 @@
package org.springframework.core.type.classreading;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -32,139 +26,68 @@ import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ReflectionUtils;
/**
* ASM method visitor which looks for the annotations defined on the method,
* exposing them through the {@link org.springframework.core.type.MethodMetadata}
* interface.
*
* @author Mark Pollack
* @author Juergen Hoeller
* @since 3.0
*/
class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
final class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
private ClassLoader classLoader;
private final String name;
private String name;
private final int access;
private int access;
private final ClassLoader classLoader;
private boolean isStatic;
private final Map<String, Map<String, Object>> attributesMap = new LinkedHashMap<String, Map<String, Object>>();
private final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>();
private final Map<String, Map<String, Object>> annotationMap = new LinkedHashMap<String, Map<String, Object>>();
public MethodMetadataReadingVisitor(ClassLoader classLoader, String name, int access) {
public MethodMetadataReadingVisitor(String name, int access, ClassLoader classLoader) {
super(new EmptyVisitor());
this.classLoader = classLoader;
this.name = name;
this.access = access;
this.isStatic = ((access & Opcodes.ACC_STATIC) != 0);
this.classLoader = classLoader;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributesMap.get(annotationType);
public String getMethodName() {
return this.name;
}
public boolean isStatic() {
return ((this.access & Opcodes.ACC_STATIC) != 0);
}
public boolean isFinal() {
return ((this.access & Opcodes.ACC_FINAL) != 0);
}
public boolean isOverridable() {
return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0));
}
public Set<String> getAnnotationTypes() {
return this.attributesMap.keySet();
}
public String getMethodName() {
return name;
}
public int getModifiers() {
return access;
return this.annotationMap.keySet();
}
public boolean hasAnnotation(String annotationType) {
return this.attributesMap.containsKey(annotationType);
return this.annotationMap.containsKey(annotationType);
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
return this.metaAnnotationMap.get(annotationType);
}
public boolean hasMetaAnnotation(String metaAnnotationType) {
Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
for (Set<String> metaTypes : allMetaTypes) {
if (metaTypes.contains(metaAnnotationType)) {
return true;
}
}
return false;
}
public boolean isStatic() {
return this.isStatic;
}
public Set<String> getAnnotationTypesWithMetaAnnotation(String metaAnnotationType) {
Set<String> annotationTypes = new LinkedHashSet<String>();
for (Map.Entry<String, Set<String>> entry : metaAnnotationMap.entrySet()) {
String attributeType = entry.getKey();
Set<String> metaAttributes = entry.getValue();
if (metaAttributes.contains(metaAnnotationType)) {
annotationTypes.add(attributeType);
}
}
return annotationTypes;
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.annotationMap.get(annotationType);
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
final String className = Type.getType(desc).getClassName();
final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
// Explicitly defined annotation attribute value.
attributes.put(name, value);
}
@Override
public void visitEnum(String name, String desc, String value) {
Object valueToUse = value;
try {
Class<?> enumType = classLoader.loadClass(Type.getType(desc).getClassName());
Field enumConstant = ReflectionUtils.findField(enumType, value);
if (enumConstant != null) {
valueToUse = enumConstant.get(null);
}
}
catch (Exception ex) {
// Class not found - can't resolve class reference in annotation attribute.
}
attributes.put(name, valueToUse);
}
@Override
public void visitEnd() {
try {
Class<?> annotationClass = classLoader.loadClass(className);
// Check declared default values of attributes in the annotation type.
Method[] annotationAttributes = annotationClass.getMethods();
for (Method annotationAttribute : annotationAttributes) {
String attributeName = annotationAttribute.getName();
Object defaultValue = annotationAttribute.getDefaultValue();
if (defaultValue != null && !attributes.containsKey(attributeName)) {
attributes.put(attributeName, defaultValue);
}
}
// Register annotations that the annotation type is annotated with.
Annotation[] metaAnnotations = annotationClass.getAnnotations();
Set<String> metaAnnotationTypeNames = new HashSet<String>();
for (Annotation metaAnnotation : metaAnnotations) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
}
metaAnnotationMap.put(className, metaAnnotationTypeNames);
}
catch (ClassNotFoundException ex) {
// Class not found
}
attributesMap.put(className, attributes);
}
};
String className = Type.getType(desc).getClassName();
return new AnnotationAttributesReadingVisitor(className, this.annotationMap, null, this.classLoader);
}
}

View File

@@ -16,7 +16,11 @@
package org.springframework.core.type.classreading;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.asm.ClassReader;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
@@ -30,7 +34,9 @@ import org.springframework.core.type.ClassMetadata;
* @author Juergen Hoeller
* @since 2.5
*/
public class SimpleMetadataReader implements MetadataReader {
final class SimpleMetadataReader implements MetadataReader {
private final Resource resource;
private final ClassReader classReader;
@@ -41,27 +47,23 @@ public class SimpleMetadataReader implements MetadataReader {
private AnnotationMetadata annotationMetadata;
SimpleMetadataReader(ClassReader classReader, ClassLoader classLoader) {
this.classReader = classReader;
SimpleMetadataReader(Resource resource, ClassLoader classLoader) throws IOException {
this.resource = resource;
InputStream is = this.resource.getInputStream();
try {
this.classReader = new ClassReader(is);
}
finally {
is.close();
}
this.classLoader = classLoader;
}
/**
* Return the underlying ASM ClassReader.
*/
public final ClassReader getClassReader() {
return this.classReader;
public Resource getResource() {
return this.resource;
}
/**
* Return the underlying ClassLoader.
*/
public final ClassLoader getClassLoader() {
return this.classLoader;
}
public ClassMetadata getClassMetadata() {
if (this.classMetadata == null) {
ClassMetadataReadingVisitor visitor = new ClassMetadataReadingVisitor();

View File

@@ -17,9 +17,7 @@
package org.springframework.core.type.classreading;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.asm.ClassReader;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -72,20 +70,14 @@ public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
}
public SimpleMetadataReader getMetadataReader(String className) throws IOException {
public MetadataReader getMetadataReader(String className) throws IOException {
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
return getMetadataReader(this.resourceLoader.getResource(resourcePath));
}
public SimpleMetadataReader getMetadataReader(Resource resource) throws IOException {
InputStream is = resource.getInputStream();
try {
return new SimpleMetadataReader(new ClassReader(is), this.resourceLoader.getClassLoader());
}
finally {
is.close();
}
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
}