Allow meta-annotations to override attributes from their parent

Issue: SPR-10181
This commit is contained in:
Juergen Hoeller
2013-08-21 17:35:56 +02:00
parent 87c2d6fd12
commit 6d3649858e
11 changed files with 434 additions and 261 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -55,7 +55,8 @@ 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.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -235,7 +236,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
for (Constructor<?> candidate : rawCandidates) {
Annotation annotation = findAutowiredAnnotation(candidate);
AnnotationAttributes annotation = findAutowiredAnnotation(candidate);
if (annotation != null) {
if (requiredConstructor != null) {
throw new BeanCreationException("Invalid autowire-marked constructor: " + candidate +
@@ -333,7 +334,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
for (Field field : targetClass.getDeclaredFields()) {
Annotation annotation = findAutowiredAnnotation(field);
AnnotationAttributes annotation = findAutowiredAnnotation(field);
if (annotation != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
@@ -347,7 +348,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
for (Method method : targetClass.getDeclaredMethods()) {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
Annotation annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
AnnotationAttributes annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
findAutowiredAnnotation(bridgedMethod) : findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
@@ -374,9 +375,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return new InjectionMetadata(clazz, elements);
}
private Annotation findAutowiredAnnotation(AccessibleObject ao) {
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
Annotation annotation = AnnotationUtils.getAnnotation(ao, type);
AnnotationAttributes annotation = AnnotatedElementUtils.getAnnotationAttributes(ao, type.getName());
if (annotation != null) {
return annotation;
}
@@ -384,6 +385,19 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return null;
}
/**
* Determine if the annotated field or method requires its dependency.
* <p>A 'required' dependency means that autowiring should fail when no beans
* are found. Otherwise, the autowiring process will simply bypass the field
* or method when no beans are found.
* @param annotation the Autowired annotation
* @return whether the annotation indicates that a dependency is required
*/
protected boolean determineRequiredStatus(AnnotationAttributes annotation) {
return (!annotation.containsKey(this.requiredParameterName) ||
this.requiredParameterValue == annotation.getBoolean(this.requiredParameterName));
}
/**
* Obtain all beans of the given type as autowire candidates.
* @param type the type of the bean
@@ -398,31 +412,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return BeanFactoryUtils.beansOfTypeIncludingAncestors(this.beanFactory, type);
}
/**
* Determine if the annotated field or method requires its dependency.
* <p>A 'required' dependency means that autowiring should fail when no beans
* are found. Otherwise, the autowiring process will simply bypass the field
* or method when no beans are found.
* @param annotation the Autowired annotation
* @return whether the annotation indicates that a dependency is required
*/
protected boolean determineRequiredStatus(Annotation annotation) {
try {
Method method = ReflectionUtils.findMethod(annotation.annotationType(), this.requiredParameterName);
if (method == null) {
// annotations like @Inject and @Value don't have a method (attribute) named "required"
// -> default to required status
return true;
}
return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, annotation));
}
catch (Exception ex) {
// an exception was thrown during reflective invocation of the required attribute
// -> default to required status
return true;
}
}
/**
* Register the specified bean as dependent on the autowired beans.
*/