Initial cut of feature to create factory beans using the @FactoryBean annotation within a @Component

This commit is contained in:
Mark Pollack 2009-03-07 07:42:25 +00:00
parent 6281948cf9
commit fc9c3009fe
15 changed files with 617 additions and 22 deletions

View File

@ -54,6 +54,7 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@ -316,19 +317,29 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
});
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
Annotation annotation = findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("Autowired annotation is not supported on static methods");
if (!isFactoryMethod(method)) {
Annotation annotation = findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("Autowired annotation is not supported on static methods");
}
if (method.getParameterTypes().length == 0) {
throw new IllegalStateException("Autowired annotation requires at least one argument: " + method);
}
boolean required = determineRequiredStatus(annotation);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new AutowiredMethodElement(method, required, pd));
}
if (method.getParameterTypes().length == 0) {
throw new IllegalStateException("Autowired annotation requires at least one argument: " + method);
}
boolean required = determineRequiredStatus(annotation);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
newMetadata.addInjectedMethod(new AutowiredMethodElement(method, required, pd));
}
}
private boolean isFactoryMethod(Method method) {
if (AnnotationUtils.findAnnotation(method, FactoryMethod.class)!= null) {
return true;
} else {
return false;
}
}
});
metadata = newMetadata;
this.injectionMetadataCache.put(clazz, metadata);

View File

@ -0,0 +1,36 @@
/*
* 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.beans.factory.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marks a method as being a factory-method of the class. Use during component scanning
* to create a bean definition that has factory-bean and factory-method metadata
*
* @author Mark Pollack
* @since 3.0
* @see RequiredAnnotationBeanPostProcessor
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface FactoryMethod {
}

View File

@ -33,7 +33,7 @@ import java.lang.annotation.Target;
* @since 2.5
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Inherited
@Documented
public @interface Qualifier {

View File

@ -0,0 +1,45 @@
/*
* Copyright 2002-2008 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.beans.factory.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marker annotation identical in functionality with <aop:scoped-proxy/> tag. Provides a smart
* proxy backed by a scoped bean, which can be injected into object instances (usually singletons)
* allowing the same reference to be held while delegating method invocations to the backing, scoped
* beans.
*
* @author Costin Leau
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ScopedProxy {
/**
* Use CGLib-based class proxies (true) or JDK interface-based (false).
*
* Default is CGLib (true).
* @return
*/
boolean proxyTargetClass() default true;
}

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.
@ -211,11 +211,33 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
}
postProcessComponentBeanDefinitions(beanDefinitions);
return beanDefinitions;
}
protected void postProcessComponentBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
//TODO refactor increment index count as part of naming strategy.
int count = 0;
Set<BeanDefinitionHolder> factoryBeanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitions) {
Set<BeanDefinition> candidates = findCandidateFactoryMethods(beanDefinitionHolder);
for (BeanDefinition candidate : candidates ) {
//TODO refactor to introduce naming strategy and some sanity checks.
String beanName = beanDefinitionHolder.getBeanName() + "$" + candidate.getFactoryMethodName() + "#" + count++;
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
factoryBeanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
beanDefinitions.addAll(factoryBeanDefinitions);
}
/**
* Apply further settings to the given bean definition,
* beyond the contents retrieved from scanning the component class.

View File

@ -17,9 +17,11 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
@ -27,13 +29,18 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@ -67,6 +74,9 @@ public class ClassPathScanningCandidateComponentProvider implements ResourceLoad
protected static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
protected static final String QUALIFIER_CLASS_NAME = "org.springframework.beans.factory.annotation.Qualifier";
protected static final String SCOPE_CLASS_NAME = "org.springframework.context.annotation.Scope";
protected final Log logger = LogFactory.getLog(getClass());
@ -223,6 +233,94 @@ public class ClassPathScanningCandidateComponentProvider implements ResourceLoad
}
return candidates;
}
public Set<BeanDefinition> findCandidateFactoryMethods(final BeanDefinitionHolder beanDefinitionHolder) {
Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
AbstractBeanDefinition containingBeanDef = (AbstractBeanDefinition)beanDefinitionHolder.getBeanDefinition();
Resource resource = containingBeanDef.getResource();
boolean debugEnabled = logger.isDebugEnabled();
boolean traceEnabled = logger.isTraceEnabled();
try {
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
Set<MethodMetadata> factoryMethodMetadataSet = metadataReader.getAnnotationMetadata().getAnnotatedMethods("org.springframework.beans.factory.annotation.FactoryMethod");
for (MethodMetadata methodMetadata : factoryMethodMetadataSet) {
if (isCandidateFactoryMethod(methodMetadata)) {
ScannedGenericBeanDefinition factoryBeanDef = new ScannedGenericBeanDefinition(metadataReader);
if (!methodMetadata.isStatic()) {
factoryBeanDef.setFactoryBeanName(beanDefinitionHolder.getBeanName());
}
factoryBeanDef.setFactoryMethodName(methodMetadata.getMethodName());
addQualifierToFactoryMethodBeanDefinition(methodMetadata, factoryBeanDef);
addScopeToFactoryMethodBeanDefinition(containingBeanDef, methodMetadata, factoryBeanDef);
factoryBeanDef.setResource(containingBeanDef.getResource());
factoryBeanDef.setSource(containingBeanDef.getSource());
if (debugEnabled) {
logger.debug("Identified candidate factory method in class: " + resource);
}
candidates.add(factoryBeanDef);
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
private void addScopeToFactoryMethodBeanDefinition(
AbstractBeanDefinition containingBeanDefinition,
MethodMetadata factoryMethodMetadata,
ScannedGenericBeanDefinition factoryBeanDefinition) {
if (factoryMethodMetadata.hasAnnotation(SCOPE_CLASS_NAME)) {
Map<String, Object> attributes = factoryMethodMetadata.getAnnotationAttributes(SCOPE_CLASS_NAME);
factoryBeanDefinition.setScope(attributes.get("value").toString());
} else {
factoryBeanDefinition.setScope(containingBeanDefinition.getScope());
}
}
protected void addQualifierToFactoryMethodBeanDefinition(MethodMetadata methodMetadata,
ScannedGenericBeanDefinition beanDef) {
//Add qualifiers to bean definition
if (methodMetadata.hasAnnotation(QUALIFIER_CLASS_NAME))
{
Map<String, Object> attributes = methodMetadata.getAnnotationAttributes(QUALIFIER_CLASS_NAME);
beanDef.addQualifier(new AutowireCandidateQualifier(Qualifier.class, attributes.get("value")));
}
if (methodMetadata.hasMetaAnnotation(QUALIFIER_CLASS_NAME))
{
//Need the attribute that has a qualifier meta-annotation.
Set<String> annotationTypes = methodMetadata.getAnnotationTypesWithMetaAnnotation(QUALIFIER_CLASS_NAME);
if (annotationTypes.size() == 1)
{
String annotationType = annotationTypes.iterator().next();
Map<String, Object> attributes = methodMetadata.getAnnotationAttributes(annotationType);
beanDef.addQualifier(new AutowireCandidateQualifier(annotationType, attributes.get("value")));
}
}
}
protected boolean isCandidateFactoryMethod(MethodMetadata methodMetadata) {
//TODO decide if we can support generic wildcard return types, parameter-less method and put in appropriate checks
return true;
}
/**
* Resolve the specified base package into a pattern specification for

View File

@ -70,5 +70,18 @@ public interface AnnotationMetadata extends ClassMetadata {
* annotation is defined.
*/
Map<String, Object> getAnnotationAttributes(String annotationType);
// TODO return null would be more consistent with other methods if no match is found
/**
* Retrieve the method meta-data 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.
*/
Set<MethodMetadata> getAnnotatedMethods(String annotationType);
}

View File

@ -0,0 +1,40 @@
package org.springframework.core.type;
import java.util.Map;
import java.util.Set;
public interface MethodMetadata {
int getModifiers();
boolean isStatic();
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);
}

View File

@ -17,7 +17,9 @@
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;
@ -96,4 +98,21 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return null;
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Method[] methods = getIntrospectedClass().getMethods();
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
Annotation[] methodAnnotations = method.getAnnotations();
for (int j = 0; j < methodAnnotations.length; j++) {
Annotation ann = methodAnnotations[j];
if (ann.annotationType().getName().equals(annotationType)) {
MethodMetadata mm = new StandardMethodMetadata(method);
annotatedMethods.add(mm);
}
}
}
return annotatedMethods;
}
}

View File

@ -0,0 +1,110 @@
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;
import java.util.Map;
import java.util.Set;
import org.springframework.core.annotation.AnnotationUtils;
public class StandardMethodMetadata implements MethodMetadata {
private final Method introspectedMethod;
public StandardMethodMetadata(Method method) {
introspectedMethod = method;
}
public final Method getIntrospectedMethod() {
return this.introspectedMethod;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (int i = 0; i < anns.length; i++) {
Annotation ann = anns[i];
if (ann.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes(ann);
}
}
return null;
}
public Set<String> getAnnotationTypes() {
Set<String> types = new HashSet<String>();
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (int i = 0; i < anns.length; i++) {
types.add(anns[i].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();
for (int i = 0; i < anns.length; i++) {
if (anns[i].annotationType().getName().equals(annotationType)) {
return true;
}
}
return false;
}
public boolean isStatic() {
return Modifier.isStatic(getIntrospectedMethod().getModifiers());
}
public Set<String> getMetaAnnotationTypes(String annotationType) {
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (int i = 0; i < anns.length; i++) {
if (anns[i].annotationType().getName().equals(annotationType)) {
Set<String> types = new HashSet<String>();
Annotation[] metaAnns = anns[i].annotationType().getAnnotations();
for (Annotation meta : metaAnns) {
types.add(meta.annotationType().getName());
}
return types;
}
}
return null;
}
public boolean hasMetaAnnotation(String metaAnnotationType) {
//TODO can refactor into shared (utility) method with StandardAnnotationMetadata
Annotation[] anns = getIntrospectedMethod().getAnnotations();
for (int i = 0; i < anns.length; i++) {
Annotation[] metaAnns = anns[i].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

@ -22,15 +22,18 @@ 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;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ReflectionUtils;
import org.springframework.core.type.MethodMetadata;
/**
* ASM class visitor which looks for the class name and implemented types as
@ -46,8 +49,9 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
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 Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>();
private final ClassLoader classLoader;
@ -55,11 +59,23 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
this.classLoader = classLoader;
}
@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;
}
@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>();
final Map<String, Object> metaAttributes = new LinkedHashMap<String, Object>();
return new EmptyVisitor() {
@Override
public void visit(String name, Object value) {
@ -107,7 +123,7 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
Annotation[] metaAnnotations = annotationClass.getAnnotations();
Set<String> metaAnnotationTypeNames = new HashSet<String>();
for (Annotation metaAnnotation : metaAnnotations) {
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
}
metaAnnotationMap.put(className, metaAnnotationTypeNames);
}
@ -115,6 +131,7 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
// Class not found - can't determine meta-annotations.
}
attributesMap.put(className, attributes);
}
};
}
@ -131,7 +148,7 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
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) {
@ -142,8 +159,21 @@ class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor imple
return false;
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributesMap.get(annotationType);
}
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (MethodMetadata method : methodMetadataSet) {
if (method.hasAnnotation(annotationType))
{
annotatedMethods.add(method);
}
}
return annotatedMethods;
}
}

View File

@ -16,6 +16,7 @@
package org.springframework.core.type.classreading;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.EmptyVisitor;
@ -33,7 +34,7 @@ import org.springframework.util.ClassUtils;
* @author Ramnivas Laddad
* @since 2.5
*/
class ClassMetadataReadingVisitor extends EmptyVisitor implements ClassMetadata {
class ClassMetadataReadingVisitor extends ClassAdapter implements ClassMetadata {
private String className;
@ -48,8 +49,12 @@ class ClassMetadataReadingVisitor extends EmptyVisitor implements ClassMetadata
private String superClassName;
private String[] interfaces;
public ClassMetadataReadingVisitor()
{
super(new EmptyVisitor());
}
@Override
public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) {
this.className = ClassUtils.convertResourcePathToClassName(name);

View File

@ -0,0 +1,139 @@
package org.springframework.core.type.classreading;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
import org.springframework.core.type.MethodMetadata;
public class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
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 ClassLoader classLoader;
private String name;
private int access;
private boolean isStatic;
public MethodMetadataReadingVisitor(ClassLoader classLoader, String name, int access) {
super(new EmptyVisitor());
this.classLoader = classLoader;
this.name = name;
this.access = access;
this.isStatic = ((access & Opcodes.ACC_STATIC) != 0);
}
public Map<String, Object> getAnnotationAttributes(String annotationType) {
return this.attributesMap.get(annotationType);
}
public Set<String> getAnnotationTypes() {
return this.attributesMap.keySet();
}
public String getMethodName() {
return name;
}
public int getModifiers() {
return access;
}
public boolean hasAnnotation(String annotationType) {
return this.attributesMap.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 isStatic;
}
public Set<String> getAnnotationTypesWithMetaAnnotation(String metaAnnotationType) {
///metaAnnotationMap.put(className, metaAnnotationTypeNames);
Set<String> annotationTypes = new LinkedHashSet<String>();
Set< Map.Entry<String, Set<String>> > metaValues = metaAnnotationMap.entrySet();
Iterator<Map.Entry<String, Set<String>> > metaIterator = metaValues.iterator();
while (metaIterator.hasNext())
{
Map.Entry<String, Set<String>> entry = metaIterator.next();
String attributeType = entry.getKey();
Set<String> metaAttributes = entry.getValue();
if (metaAttributes.contains(metaAnnotationType))
{
annotationTypes.add(attributeType);
}
}
return annotationTypes;
}
@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 visitEnd() {
try {
Class annotationClass = classLoader.loadClass(className);
// Check declared default values of attributes in the annotation type.
Method[] annotationAttributes = annotationClass.getMethods();
for (int i = 0; i < annotationAttributes.length; i++) {
Method annotationAttribute = annotationAttributes[i];
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);
}
};
}
}

View File

@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

View File

@ -23,9 +23,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import java.util.Set;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@ -37,15 +40,18 @@ import org.springframework.stereotype.Component;
*/
public class AnnotationMetadataTests extends TestCase {
public void testStandardAnnotationMetadata() throws IOException {
StandardAnnotationMetadata annInfo = new StandardAnnotationMetadata(AnnotatedComponent.class);
doTestAnnotationInfo(annInfo);
doTestMethodAnnotationInfo(annInfo);
}
public void testAsmAnnotationMetadata() throws IOException {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName());
doTestAnnotationInfo(metadataReader.getAnnotationMetadata());
doTestMethodAnnotationInfo(metadataReader.getAnnotationMetadata());
}
private void doTestAnnotationInfo(AnnotationMetadata metadata) {
@ -77,6 +83,16 @@ public class AnnotationMetadataTests extends TestCase {
assertEquals(String.class, specialAttrs.get("clazz"));
assertEquals(Thread.State.NEW, specialAttrs.get("state"));
}
private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods("org.springframework.beans.factory.annotation.Autowired");
assertEquals(1, methods.size());
for (MethodMetadata methodMetadata : methods) {
Set<String> annotationTypes = methodMetadata.getAnnotationTypes();
assertEquals(1, annotationTypes.size());
}
}
@Target(ElementType.TYPE)
@ -93,6 +109,17 @@ public class AnnotationMetadataTests extends TestCase {
@Scope("myScope")
@SpecialAttr(clazz = String.class, state = Thread.State.NEW)
private static class AnnotatedComponent implements Serializable {
@Autowired
public void doWork(@Qualifier("myColor") java.awt.Color color) {
}
@Test
public void doSleep()
{
}
}
}