@Primary/@Lazy/@DependsOn supported as meta-annotations; @Bean supported as meta-annotation on factory methods as well
This commit is contained in:
parent
a4bbd9abda
commit
f519406c37
|
|
@ -205,14 +205,14 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
|
||||||
}
|
}
|
||||||
if (candidate instanceof AnnotatedBeanDefinition) {
|
if (candidate instanceof AnnotatedBeanDefinition) {
|
||||||
AnnotatedBeanDefinition abd = (AnnotatedBeanDefinition) candidate;
|
AnnotatedBeanDefinition abd = (AnnotatedBeanDefinition) candidate;
|
||||||
if (abd.getMetadata().hasAnnotation(Primary.class.getName())) {
|
if (abd.getMetadata().isAnnotated(Primary.class.getName())) {
|
||||||
abd.setPrimary(true);
|
abd.setPrimary(true);
|
||||||
}
|
}
|
||||||
if (abd.getMetadata().hasAnnotation(Lazy.class.getName())) {
|
if (abd.getMetadata().isAnnotated(Lazy.class.getName())) {
|
||||||
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
|
Boolean value = (Boolean) abd.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value");
|
||||||
abd.setLazyInit(value);
|
abd.setLazyInit(value);
|
||||||
}
|
}
|
||||||
if (abd.getMetadata().hasAnnotation(DependsOn.class.getName())) {
|
if (abd.getMetadata().isAnnotated(DependsOn.class.getName())) {
|
||||||
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
||||||
abd.setDependsOn(value);
|
abd.setDependsOn(value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ final class ConfigurationClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A configuration class may not be final (CGLIB limitation)
|
// A configuration class may not be final (CGLIB limitation)
|
||||||
if (getMetadata().hasAnnotation(Configuration.class.getName())) {
|
if (getMetadata().isAnnotated(Configuration.class.getName())) {
|
||||||
if (getMetadata().isFinal()) {
|
if (getMetadata().isFinal()) {
|
||||||
problemReporter.error(new FinalConfigurationProblem());
|
problemReporter.error(new FinalConfigurationProblem());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.core.type.MethodMetadata;
|
import org.springframework.core.type.MethodMetadata;
|
||||||
|
|
@ -128,11 +129,11 @@ class ConfigurationClassBeanDefinitionReader {
|
||||||
List<String> names = new ArrayList<String>(Arrays.asList((String[]) beanAttributes.get("name")));
|
List<String> names = new ArrayList<String>(Arrays.asList((String[]) beanAttributes.get("name")));
|
||||||
String beanName = (names.size() > 0 ? names.remove(0) : method.getMetadata().getMethodName());
|
String beanName = (names.size() > 0 ? names.remove(0) : method.getMetadata().getMethodName());
|
||||||
for (String alias : names) {
|
for (String alias : names) {
|
||||||
registry.registerAlias(beanName, alias);
|
this.registry.registerAlias(beanName, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
// has this already been overriden (i.e.: via XML)?
|
// has this already been overriden (i.e.: via XML)?
|
||||||
if (registry.containsBeanDefinition(beanName)) {
|
if (this.registry.containsBeanDefinition(beanName)) {
|
||||||
BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
|
BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
|
||||||
// is the existing bean definition one that was created from a configuration class?
|
// is the existing bean definition one that was created from a configuration class?
|
||||||
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
|
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
|
||||||
|
|
@ -146,19 +147,19 @@ class ConfigurationClassBeanDefinitionReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata.hasAnnotation(Primary.class.getName())) {
|
if (metadata.isAnnotated(Primary.class.getName())) {
|
||||||
beanDef.setPrimary(true);
|
beanDef.setPrimary(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// is this bean to be instantiated lazily?
|
// is this bean to be instantiated lazily?
|
||||||
if (metadata.hasAnnotation(Lazy.class.getName())) {
|
if (metadata.isAnnotated(Lazy.class.getName())) {
|
||||||
beanDef.setLazyInit((Boolean) metadata.getAnnotationAttributes(Lazy.class.getName()).get("value"));
|
beanDef.setLazyInit((Boolean) metadata.getAnnotationAttributes(Lazy.class.getName()).get("value"));
|
||||||
}
|
}
|
||||||
else if (configClass.getMetadata().hasAnnotation(Lazy.class.getName())){
|
else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())){
|
||||||
beanDef.setLazyInit((Boolean) configClass.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"));
|
beanDef.setLazyInit((Boolean) configClass.getMetadata().getAnnotationAttributes(Lazy.class.getName()).get("value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata.hasAnnotation(DependsOn.class.getName())) {
|
if (metadata.isAnnotated(DependsOn.class.getName())) {
|
||||||
String[] dependsOn = (String[]) metadata.getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
String[] dependsOn = (String[]) metadata.getAnnotationAttributes(DependsOn.class.getName()).get("value");
|
||||||
if (dependsOn.length > 0) {
|
if (dependsOn.length > 0) {
|
||||||
beanDef.setDependsOn(dependsOn);
|
beanDef.setDependsOn(dependsOn);
|
||||||
|
|
@ -232,7 +233,7 @@ class ConfigurationClassBeanDefinitionReader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFactoryMethod(Method candidate) {
|
public boolean isFactoryMethod(Method candidate) {
|
||||||
return (super.isFactoryMethod(candidate) && candidate.isAnnotationPresent(Bean.class));
|
return (super.isFactoryMethod(candidate) && AnnotationUtils.findAnnotation(candidate, Bean.class) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ final class ConfigurationClassMethod {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(ProblemReporter problemReporter) {
|
public void validate(ProblemReporter problemReporter) {
|
||||||
if (this.declaringClass.getMetadata().hasAnnotation(Configuration.class.getName()) && !getMetadata().isOverridable()) {
|
if (this.declaringClass.getMetadata().isAnnotated(Configuration.class.getName()) && !getMetadata().isOverridable()) {
|
||||||
problemReporter.error(new NonOverridableMethodError());
|
problemReporter.error(new NonOverridableMethodError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class ConfigurationClassParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
|
protected void doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
|
||||||
if (metadata.hasAnnotation(Import.class.getName())) {
|
if (metadata.isAnnotated(Import.class.getName())) {
|
||||||
processImport(configClass, (String[]) metadata.getAnnotationAttributes(Import.class.getName()).get("value"));
|
processImport(configClass, (String[]) metadata.getAnnotationAttributes(Import.class.getName()).get("value"));
|
||||||
}
|
}
|
||||||
Set<MethodMetadata> methods = metadata.getAnnotatedMethods(Bean.class.getName());
|
Set<MethodMetadata> methods = metadata.getAnnotatedMethods(Bean.class.getName());
|
||||||
|
|
@ -146,7 +146,7 @@ class ConfigurationClassParser {
|
||||||
private void processClassToImport(String classToImport) throws IOException {
|
private void processClassToImport(String classToImport) throws IOException {
|
||||||
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(classToImport);
|
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(classToImport);
|
||||||
AnnotationMetadata metadata = reader.getAnnotationMetadata();
|
AnnotationMetadata metadata = reader.getAnnotationMetadata();
|
||||||
if (!metadata.hasAnnotation(Configuration.class.getName())) {
|
if (!metadata.isAnnotated(Configuration.class.getName())) {
|
||||||
this.problemReporter.error(
|
this.problemReporter.error(
|
||||||
new NonAnnotatedConfigurationProblem(metadata.getClassName(), reader.getResource(), metadata));
|
new NonAnnotatedConfigurationProblem(metadata.getClassName(), reader.getResource(), metadata));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,11 +218,11 @@ public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata != null) {
|
if (metadata != null) {
|
||||||
if (metadata.hasAnnotation(Configuration.class.getName())) {
|
if (metadata.isAnnotated(Configuration.class.getName())) {
|
||||||
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
|
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (metadata.hasAnnotation(Component.class.getName())) {
|
else if (metadata.isAnnotated(Component.class.getName())) {
|
||||||
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
|
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,9 @@ public class ScopingTests {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
|
if (ctx != null) {
|
||||||
ctx.close();
|
ctx.close();
|
||||||
|
}
|
||||||
ctx = null;
|
ctx = null;
|
||||||
customScope = null;
|
customScope = null;
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +330,6 @@ public class ScopingTests {
|
||||||
return tb;
|
return tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@MyProxiedScope
|
@MyProxiedScope
|
||||||
public TestBean scopedProxyClass() {
|
public TestBean scopedProxyClass() {
|
||||||
TestBean tb = new TestBean();
|
TestBean tb = new TestBean();
|
||||||
|
|
@ -361,6 +362,7 @@ public class ScopingTests {
|
||||||
|
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Bean
|
||||||
@Scope(value=SCOPE, proxyMode=ScopedProxyMode.TARGET_CLASS)
|
@Scope(value=SCOPE, proxyMode=ScopedProxyMode.TARGET_CLASS)
|
||||||
@interface MyProxiedScope {
|
@interface MyProxiedScope {
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.context.annotation5;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
*/
|
||||||
|
@Target({ElementType.TYPE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Repository
|
||||||
|
@Primary
|
||||||
|
@Lazy
|
||||||
|
public @interface MyRepository {
|
||||||
|
}
|
||||||
|
|
@ -25,8 +25,7 @@ import org.springframework.stereotype.Repository;
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
@Repository
|
@MyRepository
|
||||||
@Primary @Lazy
|
|
||||||
public class OtherFooDao implements FooDao {
|
public class OtherFooDao implements FooDao {
|
||||||
|
|
||||||
public String findFoo(int id) {
|
public String findFoo(int id) {
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,21 @@ public interface AnnotationMetadata extends ClassMetadata {
|
||||||
*/
|
*/
|
||||||
boolean hasMetaAnnotation(String metaAnnotationType);
|
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,
|
* 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
|
* @param annotationType the annotation type to look for
|
||||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
* @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
|
* 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
|
* Retrieve the method metadata for all methods that are annotated
|
||||||
* with at least one annotation type.
|
* (or meta-annotated) with the given annotation type.
|
||||||
* @return a Set of {@link MethodMetadata} for methods that have annotations.
|
* <p>For any returned method, {@link MethodMetadata#isAnnotated} will
|
||||||
* The return value will be an empty set if no annotated methods are found.
|
* return <code>true</code> for the given annotation type.
|
||||||
*/
|
|
||||||
Set<MethodMetadata> getAnnotatedMethods();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the method metadata for all methods that have the
|
|
||||||
* given annotation type.
|
|
||||||
* @param annotationType the annotation type to look for
|
* @param annotationType the annotation type to look for
|
||||||
* @return a Set of {@link MethodMetadata} for methods that have a matching
|
* @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
|
* annotation. The return value will be an empty set if no methods match
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,13 @@
|
||||||
package org.springframework.core.type;
|
package org.springframework.core.type;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines abstract access to the annotations of a specific
|
* 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.
|
* class, in a form that does not require that class to be loaded yet.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Mark Pollack
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see StandardMethodMetadata
|
* @see StandardMethodMetadata
|
||||||
* @see AnnotationMetadata#getAnnotatedMethods
|
* @see AnnotationMetadata#getAnnotatedMethods
|
||||||
|
|
@ -53,22 +52,17 @@ public interface MethodMetadata {
|
||||||
boolean isOverridable();
|
boolean isOverridable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the names of all annotation types defined on the underlying method.
|
* Determine whether the underlying method has an annotation or
|
||||||
* @return the annotation type names, or an empty Set if none found
|
* meta-annotation of the given type defined.
|
||||||
*/
|
|
||||||
Set<String> getAnnotationTypes();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the underlying method has an annotation of the given
|
|
||||||
* type defined.
|
|
||||||
* @param annotationType the annotation type to look for
|
* @param annotationType the annotation type to look for
|
||||||
* @return whether a matching annotation is defined
|
* @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,
|
* 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
|
* @param annotationType the annotation type to look for
|
||||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
* @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
|
* and the defined attribute value as Map value. This return value will be
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,21 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||||
return false;
|
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) {
|
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||||
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
||||||
for (Annotation ann : anns) {
|
for (Annotation ann : anns) {
|
||||||
|
|
@ -113,25 +128,22 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||||
return null;
|
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) {
|
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
|
||||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
Annotation[] methodAnnotations = method.getAnnotations();
|
for (Annotation ann : method.getAnnotations()) {
|
||||||
for (Annotation ann : methodAnnotations) {
|
|
||||||
if (ann.annotationType().getName().equals(annotationType)) {
|
if (ann.annotationType().getName().equals(annotationType)) {
|
||||||
annotatedMethods.add(new StandardMethodMetadata(method));
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,7 @@ package org.springframework.core.type;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
@ -30,8 +28,8 @@ import org.springframework.util.Assert;
|
||||||
* {@link MethodMetadata} implementation that uses standard reflection
|
* {@link MethodMetadata} implementation that uses standard reflection
|
||||||
* to introspect a given <code>Method</code>.
|
* to introspect a given <code>Method</code>.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Mark Pollack
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class StandardMethodMetadata implements MethodMetadata {
|
public class StandardMethodMetadata implements MethodMetadata {
|
||||||
|
|
@ -72,21 +70,17 @@ public class StandardMethodMetadata implements MethodMetadata {
|
||||||
return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers()));
|
return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getAnnotationTypes() {
|
public boolean isAnnotated(String annotationType) {
|
||||||
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) {
|
|
||||||
Annotation[] anns = this.introspectedMethod.getAnnotations();
|
Annotation[] anns = this.introspectedMethod.getAnnotations();
|
||||||
for (Annotation ann : anns) {
|
for (Annotation ann : anns) {
|
||||||
if (ann.annotationType().getName().equals(annotationType)) {
|
if (ann.annotationType().getName().equals(annotationType)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||||
|
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ import java.util.Set;
|
||||||
import org.springframework.asm.AnnotationVisitor;
|
import org.springframework.asm.AnnotationVisitor;
|
||||||
import org.springframework.asm.Type;
|
import org.springframework.asm.Type;
|
||||||
import org.springframework.asm.commons.EmptyVisitor;
|
import org.springframework.asm.commons.EmptyVisitor;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASM visitor which looks for the annotations defined on a class or method.
|
* 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 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 Map<String, Set<String>> metaAnnotationMap;
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
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(
|
public AnnotationAttributesReadingVisitor(
|
||||||
|
|
@ -56,7 +56,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
|
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
|
||||||
|
|
||||||
this.annotationType = annotationType;
|
this.annotationType = annotationType;
|
||||||
this.annotationMap = attributesMap;
|
this.attributesMap = attributesMap;
|
||||||
this.metaAnnotationMap = metaAnnotationMap;
|
this.metaAnnotationMap = metaAnnotationMap;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
if (valueToUse instanceof Type) {
|
if (valueToUse instanceof Type) {
|
||||||
valueToUse = ((Type) value).getClassName();
|
valueToUse = ((Type) value).getClassName();
|
||||||
}
|
}
|
||||||
this.attributes.put(name, valueToUse);
|
this.localAttributes.put(name, valueToUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitEnum(String name, String desc, String value) {
|
public void visitEnum(String name, String desc, String value) {
|
||||||
|
|
@ -82,7 +82,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
// Class not found - can't resolve class reference in annotation attribute.
|
// 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) {
|
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||||
|
|
@ -96,7 +96,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
if (newValue instanceof Type) {
|
if (newValue instanceof Type) {
|
||||||
newValue = ((Type) value).getClassName();
|
newValue = ((Type) value).getClassName();
|
||||||
}
|
}
|
||||||
Object existingValue = attributes.get(attrName);
|
Object existingValue = localAttributes.get(attrName);
|
||||||
if (existingValue != null) {
|
if (existingValue != null) {
|
||||||
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
|
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue);
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +105,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
newArray[0] = newValue;
|
newArray[0] = newValue;
|
||||||
newValue = newArray;
|
newValue = newArray;
|
||||||
}
|
}
|
||||||
attributes.put(attrName, newValue);
|
localAttributes.put(attrName, newValue);
|
||||||
}
|
}
|
||||||
public void visitEnum(String name, String desc, String value) {
|
public void visitEnum(String name, String desc, String value) {
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitEnd() {
|
public void visitEnd() {
|
||||||
this.annotationMap.put(this.annotationType, this.attributes);
|
this.attributesMap.put(this.annotationType, this.localAttributes);
|
||||||
try {
|
try {
|
||||||
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
|
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
|
||||||
// Check declared default values of attributes in the annotation type.
|
// Check declared default values of attributes in the annotation type.
|
||||||
|
|
@ -129,23 +129,23 @@ final class AnnotationAttributesReadingVisitor implements AnnotationVisitor {
|
||||||
for (Method annotationAttribute : annotationAttributes) {
|
for (Method annotationAttribute : annotationAttributes) {
|
||||||
String attributeName = annotationAttribute.getName();
|
String attributeName = annotationAttribute.getName();
|
||||||
Object defaultValue = annotationAttribute.getDefaultValue();
|
Object defaultValue = annotationAttribute.getDefaultValue();
|
||||||
if (defaultValue != null && !this.attributes.containsKey(attributeName)) {
|
if (defaultValue != null && !this.localAttributes.containsKey(attributeName)) {
|
||||||
this.attributes.put(attributeName, defaultValue);
|
this.localAttributes.put(attributeName, defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Register annotations that the annotation type is annotated with.
|
// Register annotations that the annotation type is annotated with.
|
||||||
if (this.metaAnnotationMap != null) {
|
|
||||||
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
|
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
|
||||||
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
|
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
|
||||||
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
|
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
|
||||||
if (!this.annotationMap.containsKey(metaAnnotation.annotationType().getName())) {
|
if (!this.attributesMap.containsKey(metaAnnotation.annotationType().getName())) {
|
||||||
this.annotationMap.put(metaAnnotation.annotationType().getName(),
|
this.attributesMap.put(metaAnnotation.annotationType().getName(),
|
||||||
AnnotationUtils.getAnnotationAttributes(metaAnnotation, true));
|
AnnotationUtils.getAnnotationAttributes(metaAnnotation, true));
|
||||||
}
|
}
|
||||||
for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) {
|
for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) {
|
||||||
metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName());
|
metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.metaAnnotationMap != null) {
|
||||||
this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames);
|
this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ import org.springframework.core.type.MethodMetadata;
|
||||||
*/
|
*/
|
||||||
final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
|
final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
|
||||||
|
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
private final Set<String> annotationSet = new LinkedHashSet<String>();
|
private final Set<String> annotationSet = new LinkedHashSet<String>();
|
||||||
|
|
||||||
private final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<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 Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>();
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
|
||||||
|
|
||||||
|
|
||||||
public AnnotationMetadataReadingVisitor(ClassLoader classLoader) {
|
public AnnotationMetadataReadingVisitor(ClassLoader classLoader) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
|
|
@ -92,24 +92,18 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
public boolean isAnnotated(String annotationType) {
|
||||||
return this.attributeMap.get(annotationType);
|
return this.attributeMap.containsKey(annotationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MethodMetadata> getAnnotatedMethods() {
|
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
return this.attributeMap.get(annotationType);
|
||||||
for (MethodMetadata method : this.methodMetadataSet) {
|
|
||||||
if (!method.getAnnotationTypes().isEmpty()) {
|
|
||||||
annotatedMethods.add(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return annotatedMethods;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
|
public Set<MethodMetadata> getAnnotatedMethods(String annotationType) {
|
||||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||||
for (MethodMetadata method : this.methodMetadataSet) {
|
for (MethodMetadata method : this.methodMetadataSet) {
|
||||||
if (method.hasAnnotation(annotationType)) {
|
if (method.isAnnotated(annotationType)) {
|
||||||
annotatedMethods.add(method);
|
annotatedMethods.add(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package org.springframework.core.type.classreading;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.asm.AnnotationVisitor;
|
import org.springframework.asm.AnnotationVisitor;
|
||||||
import org.springframework.asm.MethodAdapter;
|
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}
|
* exposing them through the {@link org.springframework.core.type.MethodMetadata}
|
||||||
* interface.
|
* interface.
|
||||||
*
|
*
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Mark Pollack
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
final class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
|
final class MethodMetadataReadingVisitor extends MethodAdapter implements MethodMetadata {
|
||||||
|
|
@ -44,7 +43,7 @@ final class MethodMetadataReadingVisitor extends MethodAdapter implements Method
|
||||||
|
|
||||||
private final ClassLoader classLoader;
|
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) {
|
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() {
|
public String getMethodName() {
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
@ -71,23 +77,12 @@ final class MethodMetadataReadingVisitor extends MethodAdapter implements Method
|
||||||
return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0));
|
return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getAnnotationTypes() {
|
public boolean isAnnotated(String annotationType) {
|
||||||
return this.annotationMap.keySet();
|
return this.attributeMap.containsKey(annotationType);
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasAnnotation(String annotationType) {
|
|
||||||
return this.annotationMap.containsKey(annotationType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||||
return this.annotationMap.get(annotationType);
|
return this.attributeMap.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,10 @@ public class AnnotationMetadataTests extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) {
|
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());
|
assertEquals(1, methods.size());
|
||||||
for (MethodMetadata methodMetadata : methods) {
|
for (MethodMetadata methodMetadata : methods) {
|
||||||
Set<String> annotationTypes = methodMetadata.getAnnotationTypes();
|
assertTrue(methodMetadata.isAnnotated(Autowired.class.getName()));
|
||||||
assertEquals(1, annotationTypes.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue