custom stereotype annotations can be meta-annotated with @Service, @Controller etc as well; @Scope and @Transactional are now supported as meta-annotations on custom annotations

This commit is contained in:
Juergen Hoeller
2009-04-26 11:41:06 +00:00
parent ac16101f98
commit cea8f7f69e
18 changed files with 289 additions and 144 deletions

View File

@@ -137,6 +137,14 @@ public abstract class AnnotationUtils {
return annotation;
}
}
if (!Annotation.class.isAssignableFrom(clazz)) {
for (Annotation ann : clazz.getAnnotations()) {
annotation = findAnnotation(ann.annotationType(), annotationType);
if (annotation != null) {
return annotation;
}
}
}
Class<?> superClass = clazz.getSuperclass();
if (superClass == null || superClass.equals(Object.class)) {
return null;

View File

@@ -37,6 +37,14 @@ public interface AnnotationMetadata extends ClassMetadata {
*/
Set<String> getAnnotationTypes();
/**
* 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);
/**
* Determine whether the underlying class has an annotation of the given
* type defined.
@@ -45,6 +53,14 @@ public interface AnnotationMetadata extends ClassMetadata {
*/
boolean hasAnnotation(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);
/**
* Retrieve the attributes of the annotation of the given type,
* if any (i.e. if defined on the underlying class).
@@ -55,22 +71,6 @@ public interface AnnotationMetadata extends ClassMetadata {
*/
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);
/**
* 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);
/**
* Retrieve the method metadata for all methods that are annotated
* with at least one annotation type.

View File

@@ -18,7 +18,6 @@ package org.springframework.core.type;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -45,7 +44,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
public Set<String> getAnnotationTypes() {
Set<String> types = new HashSet<String>();
Set<String> types = new LinkedHashSet<String>();
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
types.add(ann.annotationType().getName());
@@ -53,6 +52,24 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return types;
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().getName().equals(annotationType)) {
Set<String> types = new LinkedHashSet<String>();
Annotation[] metaAnns = ann.annotationType().getAnnotations();
for (Annotation metaAnn : metaAnns) {
types.add(metaAnn.annotationType().getName());
for (Annotation metaMetaAnn : metaAnn.annotationType().getAnnotations()) {
types.add(metaMetaAnn.annotationType().getName());
}
}
return types;
}
}
return null;
}
public boolean hasAnnotation(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
@@ -63,42 +80,37 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return false;
}
public boolean hasMetaAnnotation(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
Annotation[] metaAnns = ann.annotationType().getAnnotations();
for (Annotation metaAnn : metaAnns) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
return true;
}
for (Annotation metaMetaAnn : metaAnn.annotationType().getAnnotations()) {
if (metaMetaAnn.annotationType().getName().equals(annotationType)) {
return true;
}
}
}
}
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) {
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 null;
}
public boolean hasMetaAnnotation(String annotationType) {
Annotation[] anns = getIntrospectedClass().getAnnotations();
for (Annotation ann : anns) {
Annotation[] metaAnns = ann.annotationType().getAnnotations();
for (Annotation meta : metaAnns) {
if (meta.annotationType().getName().equals(annotationType)) {
return true;
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(metaAnn, true);
}
}
}
return false;
return null;
}
public Set<MethodMetadata> getAnnotatedMethods() {

View File

@@ -20,8 +20,8 @@ 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.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -30,6 +30,7 @@ import org.springframework.asm.Type;
import org.springframework.asm.commons.EmptyVisitor;
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.
@@ -47,7 +48,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
private final ClassLoader classLoader;
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
public AnnotationAttributesReadingVisitor(
@@ -120,6 +121,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
}
public void visitEnd() {
this.annotationMap.put(this.annotationType, this.attributes);
try {
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
// Check declared default values of attributes in the annotation type.
@@ -133,10 +135,16 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
}
// 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) {
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());
}
}
this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames);
}
@@ -144,7 +152,6 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
catch (ClassNotFoundException ex) {
// Class not found - can't determine meta-annotations.
}
this.annotationMap.put(this.annotationType, this.attributes);
}
}

View File

@@ -39,10 +39,12 @@ import org.springframework.core.type.MethodMetadata;
*/
final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
private final Map<String, Map<String, Object>> annotationMap = new LinkedHashMap<String, Map<String, Object>>();
private final Set<String> annotationSet = new LinkedHashSet<String>();
private final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>();
private final Map<String, Map<String, Object>> attributeMap = new LinkedHashMap<String, Map<String, Object>>();
private final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>();
private final ClassLoader classLoader;
@@ -63,26 +65,23 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
@Override
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
String className = Type.getType(desc).getClassName();
return new AnnotationAttributesReadingVisitor(className, this.annotationMap, this.metaAnnotationMap, this.classLoader);
this.annotationSet.add(className);
return new AnnotationAttributesReadingVisitor(className, this.attributeMap, this.metaAnnotationMap, this.classLoader);
}
public Set<String> getAnnotationTypes() {
return this.annotationMap.keySet();
}
public boolean hasAnnotation(String annotationType) {
return this.annotationMap.containsKey(annotationType);
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.annotationMap.get(annotationType);
return this.annotationSet;
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
return this.metaAnnotationMap.get(annotationType);
}
public boolean hasAnnotation(String annotationType) {
return this.annotationSet.contains(annotationType);
}
public boolean hasMetaAnnotation(String metaAnnotationType) {
Collection<Set<String>> allMetaTypes = this.metaAnnotationMap.values();
for (Set<String> metaTypes : allMetaTypes) {
@@ -93,6 +92,10 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributeMap.get(annotationType);
}
public Set<MethodMetadata> getAnnotatedMethods() {
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (MethodMetadata method : this.methodMetadataSet) {

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.
@@ -77,8 +77,8 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
}
else if (superClassName.startsWith("java.")) {
try {
Class clazz = getClass().getClassLoader().loadClass(superClassName);
return Boolean.valueOf(clazz.getAnnotation(this.annotationType) != null);
Class<?> clazz = getClass().getClassLoader().loadClass(superClassName);
return (clazz.getAnnotation(this.annotationType) != null);
}
catch (ClassNotFoundException ex) {
// Class not found - can't determine a match that way.