Consistent bridge method handling in annotation post-processors
Issue: SPR-12495
Issue: SPR-12187
(cherry picked from commit d97add0)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -379,13 +379,28 @@ public abstract class BeanUtils {
|
||||
* Find a JavaBeans {@code PropertyDescriptor} for the given method,
|
||||
* with the method either being the read method or the write method for
|
||||
* that bean property.
|
||||
* @param method the method to find a corresponding PropertyDescriptor for
|
||||
* @param method the method to find a corresponding PropertyDescriptor for,
|
||||
* introspecting its declaring class
|
||||
* @return the corresponding PropertyDescriptor, or {@code null} if none
|
||||
* @throws BeansException if PropertyDescriptor lookup fails
|
||||
*/
|
||||
public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException {
|
||||
return findPropertyForMethod(method, method.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a JavaBeans {@code PropertyDescriptor} for the given method,
|
||||
* with the method either being the read method or the write method for
|
||||
* that bean property.
|
||||
* @param method the method to find a corresponding PropertyDescriptor for
|
||||
* @param clazz the (most specific) class to introspect for descriptors
|
||||
* @return the corresponding PropertyDescriptor, or {@code null} if none
|
||||
* @throws BeansException if PropertyDescriptor lookup fails
|
||||
* @since 3.2.13
|
||||
*/
|
||||
public static PropertyDescriptor findPropertyForMethod(Method method, Class<?> clazz) throws BeansException {
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
PropertyDescriptor[] pds = getPropertyDescriptors(method.getDeclaringClass());
|
||||
PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod())) {
|
||||
return pd;
|
||||
@@ -591,11 +606,11 @@ public abstract class BeanUtils {
|
||||
actualEditable = editable;
|
||||
}
|
||||
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
|
||||
List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;
|
||||
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
|
||||
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
|
||||
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if (sourcePd != null) {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
|
||||
@@ -233,8 +233,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
Constructor<?> requiredConstructor = null;
|
||||
Constructor<?> defaultConstructor = null;
|
||||
for (Constructor<?> candidate : rawCandidates) {
|
||||
Annotation annotation = findAutowiredAnnotation(candidate);
|
||||
if (annotation != null) {
|
||||
Annotation ann = findAutowiredAnnotation(candidate);
|
||||
if (ann != null) {
|
||||
if (requiredConstructor != null) {
|
||||
throw new BeanCreationException(beanName,
|
||||
"Invalid autowire-marked constructor: " + candidate +
|
||||
@@ -245,7 +245,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
throw new IllegalStateException(
|
||||
"Autowired annotation requires at least one argument: " + candidate);
|
||||
}
|
||||
boolean required = determineRequiredStatus(annotation);
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
if (required) {
|
||||
if (!candidates.isEmpty()) {
|
||||
throw new BeanCreationException(beanName,
|
||||
@@ -319,9 +319,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
|
||||
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz) {
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
// Fall back to class name as cache key, for backwards compatibility with custom callers.
|
||||
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
|
||||
// Quick check on the concurrent map first, with minimal locking.
|
||||
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
|
||||
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
|
||||
synchronized (this.injectionMetadataCache) {
|
||||
@@ -342,23 +342,25 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
do {
|
||||
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
|
||||
for (Field field : targetClass.getDeclaredFields()) {
|
||||
Annotation annotation = findAutowiredAnnotation(field);
|
||||
if (annotation != null) {
|
||||
Annotation ann = findAutowiredAnnotation(field);
|
||||
if (ann != null) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static fields: " + field);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
boolean required = determineRequiredStatus(annotation);
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
currElements.add(new AutowiredFieldElement(field, required));
|
||||
}
|
||||
}
|
||||
for (Method method : targetClass.getDeclaredMethods()) {
|
||||
Annotation ann = null;
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
Annotation annotation = BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod) ?
|
||||
findAutowiredAnnotation(bridgedMethod) : findAutowiredAnnotation(method);
|
||||
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
|
||||
ann = findAutowiredAnnotation(bridgedMethod);
|
||||
}
|
||||
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Autowired annotation is not supported on static methods: " + method);
|
||||
@@ -370,8 +372,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
logger.warn("Autowired annotation should be used on methods with actual parameters: " + method);
|
||||
}
|
||||
}
|
||||
boolean required = determineRequiredStatus(annotation);
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
|
||||
boolean required = determineRequiredStatus(ann);
|
||||
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
|
||||
currElements.add(new AutowiredMethodElement(method, required, pd));
|
||||
}
|
||||
}
|
||||
@@ -385,9 +387,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
|
||||
private Annotation findAutowiredAnnotation(AccessibleObject ao) {
|
||||
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
|
||||
Annotation annotation = AnnotationUtils.getAnnotation(ao, type);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
Annotation ann = AnnotationUtils.getAnnotation(ao, type);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -412,21 +414,21 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||
* <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
|
||||
* @param ann the Autowired annotation
|
||||
* @return whether the annotation indicates that a dependency is required
|
||||
*/
|
||||
protected boolean determineRequiredStatus(Annotation annotation) {
|
||||
protected boolean determineRequiredStatus(Annotation ann) {
|
||||
try {
|
||||
Method method = ReflectionUtils.findMethod(annotation.annotationType(), this.requiredParameterName);
|
||||
Method method = ReflectionUtils.findMethod(ann.annotationType(), this.requiredParameterName);
|
||||
if (method == null) {
|
||||
// annotations like @Inject and @Value don't have a method (attribute) named "required"
|
||||
// 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));
|
||||
return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, ann));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// an exception was thrown during reflective invocation of the required attribute
|
||||
// An exception was thrown during reflective invocation of the required attribute
|
||||
// -> default to required status
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user