@Primary/@Lazy/@DependsOn supported as meta-annotations; @Bean supported as meta-annotation on factory methods as well

This commit is contained in:
Juergen Hoeller
2009-07-22 15:23:22 +00:00
parent a4bbd9abda
commit f519406c37
17 changed files with 156 additions and 123 deletions

View File

@@ -61,9 +61,21 @@ public interface AnnotationMetadata extends ClassMetadata {
*/
boolean hasMetaAnnotation(String metaAnnotationType);
/**
* Determine whether the underlying class has an annotation or
* meta-annotation of the given type defined.
* <p>This is equivalent to a "hasAnnotation || hasMetaAnnotation"
* check. If this method returns <code>true</code>, then
* {@link #getAnnotationAttributes} will return a non-null Map.
* @param annotationType the annotation type to look for
* @return whether a matching annotation is defined
*/
boolean isAnnotated(String annotationType);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying class).
* if any (i.e. if defined on the underlying class, as direct
* annotation or as meta-annotation).
* @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
@@ -73,15 +85,9 @@ public interface AnnotationMetadata extends ClassMetadata {
/**
* 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.
*/
Set<MethodMetadata> getAnnotatedMethods();
/**
* Retrieve the method metadata for all methods that have the
* given annotation type.
* (or meta-annotated) with the given annotation type.
* <p>For any returned method, {@link MethodMetadata#isAnnotated} will
* return <code>true</code> for 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

View File

@@ -17,14 +17,13 @@
package org.springframework.core.type;
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
* @author Mark Pollack
* @since 3.0
* @see StandardMethodMetadata
* @see AnnotationMetadata#getAnnotatedMethods
@@ -53,22 +52,17 @@ public interface MethodMetadata {
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.
* Determine whether the underlying method has an annotation or
* meta-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);
boolean isAnnotated(String annotationType);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying method).
* if any (i.e. if defined on the underlying method, as direct
* annotation or as meta-annotation).
* @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

View File

@@ -98,6 +98,21 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return false;
}
public boolean isAnnotated(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return true;
}
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
return true;
}
}
}
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
@@ -113,25 +128,22 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return null;
}
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 annotatedMethods;
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Method[] methods = getIntrospectedClass().getDeclaredMethods();
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (Method method : methods) {
Annotation[] methodAnnotations = method.getAnnotations();
for (Annotation ann : methodAnnotations) {
for (Annotation ann : method.getAnnotations()) {
if (ann.annotationType().getName().equals(annotationType)) {
annotatedMethods.add(new StandardMethodMetadata(method));
break;
}
else {
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
annotatedMethods.add(new StandardMethodMetadata(method));
break;
}
}
}
}
}

View File

@@ -19,9 +19,7 @@ package org.springframework.core.type;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -30,8 +28,8 @@ 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
* @author Mark Pollack
* @since 3.0
*/
public class StandardMethodMetadata implements MethodMetadata {
@@ -72,21 +70,17 @@ public class StandardMethodMetadata implements MethodMetadata {
return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers()));
}
public Set<String> getAnnotationTypes() {
Set<String> types = new HashSet<String>();
Annotation[] anns = this.introspectedMethod.getAnnotations();
for (Annotation ann : anns) {
types.add(ann.annotationType().getName());
}
return types;
}
public boolean hasAnnotation(String annotationType) {
public boolean isAnnotated(String annotationType) {
Annotation[] anns = this.introspectedMethod.getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
return true;
}
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
return true;
}
}
}
return false;
}

View File

@@ -28,9 +28,9 @@ import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.core.annotation.AnnotationUtils;
/**
* ASM visitor which looks for the annotations defined on a class or method.
@@ -42,13 +42,13 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
private final String annotationType;
private final Map<String, Map<String, Object>> annotationMap;
private final Map<String, Map<String, Object>> attributesMap;
private final Map<String, Set<String>> metaAnnotationMap;
private final ClassLoader classLoader;
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
private final Map<String, Object> localAttributes = new LinkedHashMap<String, Object>();
public AnnotationAttributesReadingVisitor(
@@ -56,7 +56,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
this.annotationType = annotationType;
this.annotationMap = attributesMap;
this.attributesMap = attributesMap;
this.metaAnnotationMap = metaAnnotationMap;
this.classLoader = classLoader;
}
@@ -67,7 +67,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
if (valueToUse instanceof Type) {
valueToUse = ((Type) value).getClassName();
}
this.attributes.put(name, valueToUse);
this.localAttributes.put(name, valueToUse);
}
public void visitEnum(String name, String desc, String value) {
@@ -82,7 +82,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
catch (Exception ex) {
// Class not found - can't resolve class reference in annotation attribute.
}
this.attributes.put(name, valueToUse);
this.localAttributes.put(name, valueToUse);
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
@@ -96,7 +96,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
if (newValue instanceof Type) {
newValue = ((Type) value).getClassName();
}
Object existingValue = attributes.get(attrName);
Object existingValue = localAttributes.get(attrName);
if (existingValue != null) {
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
}
@@ -105,7 +105,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
newArray[0] = newValue;
newValue = newArray;
}
attributes.put(attrName, newValue);
localAttributes.put(attrName, newValue);
}
public void visitEnum(String name, String desc, String value) {
}
@@ -121,7 +121,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
}
public void visitEnd() {
this.annotationMap.put(this.annotationType, this.attributes);
this.attributesMap.put(this.annotationType, this.localAttributes);
try {
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
// Check declared default values of attributes in the annotation type.
@@ -129,23 +129,23 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
for (Method annotationAttribute : annotationAttributes) {
String attributeName = annotationAttribute.getName();
Object defaultValue = annotationAttribute.getDefaultValue();
if (defaultValue != null && !this.attributes.containsKey(attributeName)) {
this.attributes.put(attributeName, defaultValue);
if (defaultValue != null && !this.localAttributes.containsKey(attributeName)) {
this.localAttributes.put(attributeName, defaultValue);
}
}
// Register annotations that the annotation type is annotated with.
if (this.metaAnnotationMap != null) {
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
if (!this.annotationMap.containsKey(metaAnnotation.annotationType().getName())) {
this.annotationMap.put(metaAnnotation.annotationType().getName(),
AnnotationUtils.getAnnotationAttributes(metaAnnotation, true));
}
for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) {
metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName());
}
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
if (!this.attributesMap.containsKey(metaAnnotation.annotationType().getName())) {
this.attributesMap.put(metaAnnotation.annotationType().getName(),
AnnotationUtils.getAnnotationAttributes(metaAnnotation, true));
}
for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) {
metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName());
}
}
if (this.metaAnnotationMap != null) {
this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames);
}
}

View File

@@ -39,6 +39,8 @@ import org.springframework.core.type.MethodMetadata;
*/
final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
private final ClassLoader classLoader;
private final Set<String> annotationSet = new LinkedHashSet<String>();
private final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>();
@@ -47,8 +49,6 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
private final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>();
private final ClassLoader classLoader;
public AnnotationMetadataReadingVisitor(ClassLoader classLoader) {
this.classLoader = classLoader;
@@ -92,24 +92,18 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributeMap.get(annotationType);
public boolean isAnnotated(String annotationType) {
return this.attributeMap.containsKey(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 Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributeMap.get(annotationType);
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (MethodMetadata method : this.methodMetadataSet) {
if (method.hasAnnotation(annotationType)) {
if (method.isAnnotated(annotationType)) {
annotatedMethods.add(method);
}
}

View File

@@ -18,7 +18,6 @@ package org.springframework.core.type.classreading;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.MethodAdapter;
@@ -32,8 +31,8 @@ import org.springframework.core.type.MethodMetadata;
* exposing them through the {@link org.springframework.core.type.MethodMetadata}
* interface.
*
* @author Mark Pollack
* @author Juergen Hoeller
* @author Mark Pollack
* @since 3.0
*/
final class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
@@ -44,7 +43,7 @@ final class MethodMetadataReadingVisitor extends MethodAdapter implements Method
private final ClassLoader classLoader;
private final Map<String, Map<String, Object>> annotationMap = new LinkedHashMap<String, Map<String, Object>>();
private final Map<String, Map<String, Object>> attributeMap = new LinkedHashMap<String, Map<String, Object>>();
public MethodMetadataReadingVisitor(String name, int access, ClassLoader classLoader) {
@@ -55,6 +54,13 @@ final class MethodMetadataReadingVisitor extends MethodAdapter implements Method
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, null, this.classLoader);
}
public String getMethodName() {
return this.name;
}
@@ -71,23 +77,12 @@ final class MethodMetadataReadingVisitor extends MethodAdapter implements Method
return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0));
}
public Set<String> getAnnotationTypes() {
return this.annotationMap.keySet();
public boolean isAnnotated(String annotationType) {
return this.attributeMap.containsKey(annotationType);
}
public boolean hasAnnotation(String annotationType) {
return this.annotationMap.containsKey(annotationType);
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.annotationMap.get(annotationType);
}
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
return new AnnotationAttributesReadingVisitor(className, this.annotationMap, null, this.classLoader);
return this.attributeMap.get(annotationType);
}
}

View File

@@ -84,11 +84,10 @@ public class AnnotationMetadataTests extends TestCase {
}
private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods("org.springframework.beans.factory.annotation.Autowired");
Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(Autowired.class.getName());
assertEquals(1, methods.size());
for (MethodMetadata methodMetadata : methods) {
Set<String> annotationTypes = methodMetadata.getAnnotationTypes();
assertEquals(1, annotationTypes.size());
assertTrue(methodMetadata.isAnnotated(Autowired.class.getName()));
}
}