From 4faa5af3f8afe6a5b901ba6e595d4cb441b63344 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 22 Jun 2011 21:25:50 +0000 Subject: [PATCH] backported bridge method detection for class hierarchies with mixed visibilities (SPR-7900) --- .../AutowiredAnnotationBeanPostProcessor.java | 30 ++++---- .../CommonAnnotationBeanPostProcessor.java | 70 ++++++++++--------- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 45247a384cf..8d483c0dadc 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -50,6 +50,7 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.BridgeMethodResolver; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.Ordered; @@ -62,7 +63,7 @@ import org.springframework.util.ReflectionUtils; * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that autowires annotated fields, setter methods and arbitrary config methods. * Such members to be injected are detected through a Java 5 annotation: - * by default, Spring's {@link Autowired} annotation. + * by default, Spring's @{@link Autowired} and @{@link Value} annotations. * *

Only one constructor (at max) of any given bean class may carry this * annotation with the 'required' parameter set to true, @@ -83,21 +84,23 @@ import org.springframework.util.ReflectionUtils; * a special case of such a general config method. Such config methods * do not have to be public. * - *

Also supports JSR-330's {@link javax.inject.Inject} annotation, if available. + *

Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation, if + * available. * *

Note: A default AutowiredAnnotationBeanPostProcessor will be registered * by the "context:annotation-config" and "context:component-scan" XML tags. * Remove or turn off the default annotation configuration there if you intend * to specify a custom AutowiredAnnotationBeanPostProcessor bean definition. - *

NOTE: Annotation injection will be performed before XML injection; thus - * the latter configuration will override the former for properties wired through - * both approaches. - * + *

NOTE: Annotation injection will be performed before XML injection; + * thus the latter configuration will override the former for properties wired through + * both approaches. + * * @author Juergen Hoeller * @author Mark Fisher * @since 2.5 * @see #setAutowiredAnnotationType * @see Autowired + * @see Value */ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { @@ -115,8 +118,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private ConfigurableListableBeanFactory beanFactory; - private final Map, Constructor[]> candidateConstructorsCache = - new ConcurrentHashMap, Constructor[]>(); + private final Map, Constructor[]> candidateConstructorsCache = + new ConcurrentHashMap, Constructor[]>(); private final Map, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap, InjectionMetadata>(); @@ -305,7 +308,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean } - private InjectionMetadata findAutowiringMetadata(Class clazz) { + private InjectionMetadata findAutowiringMetadata(Class clazz) { // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { @@ -320,7 +323,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean return metadata; } - private InjectionMetadata buildAutowiringMetadata(Class clazz) { + private InjectionMetadata buildAutowiringMetadata(Class clazz) { LinkedList elements = new LinkedList(); Class targetClass = clazz; @@ -368,6 +371,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean private Annotation findAutowiredAnnotation(AccessibleObject ao) { for (Class type : this.autowiredAnnotationTypes) { + if (ao instanceof Method) { + ao = BridgeMethodResolver.findBridgedMethod((Method) ao); + } Annotation annotation = ao.getAnnotation(type); if (annotation != null) { return annotation; @@ -534,7 +540,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean arguments = resolveCachedArguments(beanName); } else { - Class[] paramTypes = method.getParameterTypes(); + Class[] paramTypes = method.getParameterTypes(); arguments = new Object[paramTypes.length]; DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length]; Set autowiredBeanNames = new LinkedHashSet(paramTypes.length); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java index d981c811a5c..6b4da5014d9 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 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. @@ -58,6 +58,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.BridgeMethodResolver; import org.springframework.core.MethodParameter; import org.springframework.core.Ordered; import org.springframework.jndi.support.SimpleJndiBeanFactory; @@ -303,7 +304,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } - private InjectionMetadata findResourceMetadata(final Class clazz) { + private InjectionMetadata findResourceMetadata(final Class clazz) { // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(clazz); if (metadata == null) { @@ -338,40 +339,41 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean } } for (Method method : targetClass.getDeclaredMethods()) { - if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass) && - method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods"); - } - if (method.getParameterTypes().length != 1) { - throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method); - } - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); - currElements.add(new WebServiceRefElement(method, pd)); - } - else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass) && - method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@EJB annotation is not supported on static methods"); - } - if (method.getParameterTypes().length != 1) { - throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method); - } - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); - currElements.add(new EjbRefElement(method, pd)); - } - else if (method.isAnnotationPresent(Resource.class) && - method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { - if (Modifier.isStatic(method.getModifiers())) { - throw new IllegalStateException("@Resource annotation is not supported on static methods"); - } - Class[] paramTypes = method.getParameterTypes(); - if (paramTypes.length != 1) { - throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method); + method = BridgeMethodResolver.findBridgedMethod(method); + Method mostSpecificMethod = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(method, clazz)); + if (method.equals(mostSpecificMethod)) { + if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass)) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods"); + } + if (method.getParameterTypes().length != 1) { + throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method); + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + currElements.add(new WebServiceRefElement(method, pd)); } - if (!ignoredResourceTypes.contains(paramTypes[0].getName())) { + else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass)) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("@EJB annotation is not supported on static methods"); + } + if (method.getParameterTypes().length != 1) { + throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method); + } PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); - currElements.add(new ResourceElement(method, pd)); + currElements.add(new EjbRefElement(method, pd)); + } + else if (method.isAnnotationPresent(Resource.class)) { + if (Modifier.isStatic(method.getModifiers())) { + throw new IllegalStateException("@Resource annotation is not supported on static methods"); + } + Class[] paramTypes = method.getParameterTypes(); + if (paramTypes.length != 1) { + throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method); + } + if (!ignoredResourceTypes.contains(paramTypes[0].getName())) { + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method); + currElements.add(new ResourceElement(method, pd)); + } } } }