Skip to content

Commit 980c15d

Browse files
committed
Distinguish between different bridge method types
Add BridgeMethodResolver#isJava6VisibilityBridgeMethodPair to distinguish between (a) bridge methods introduced in Java 6 to compensate for inheriting public methods from non-public superclasses and (b) bridge methods that have existed since Java 5 to accommodate return type covariance and generic parameters. In the former case, annotations should be looked up from the original bridged method (SPR-7900). In the latter, the annotation should be looked up against the bridge method itself (SPR-8660). As noted in the Javadoc for the new method, see http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html for a useful description of the various types of bridge methods, as well as http://bugs.sun.com/view_bug.do?bug_id=6342411, the bug fixed in Java 6 resulting in the introduction of 'visibility bridge methods'. Issue: SPR-8660, SPR-7900
1 parent 6248135 commit 980c15d

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.beans.factory.annotation;
1818

19+
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
20+
import static org.springframework.core.BridgeMethodResolver.isJava6VisibilityBridgeMethodPair;
21+
1922
import java.beans.PropertyDescriptor;
2023
import java.lang.annotation.Annotation;
2124
import java.lang.reflect.AccessibleObject;
@@ -35,7 +38,6 @@
3538

3639
import org.apache.commons.logging.Log;
3740
import org.apache.commons.logging.LogFactory;
38-
3941
import org.springframework.beans.BeanUtils;
4042
import org.springframework.beans.BeansException;
4143
import org.springframework.beans.PropertyValues;
@@ -50,7 +52,6 @@
5052
import org.springframework.beans.factory.config.RuntimeBeanReference;
5153
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
5254
import org.springframework.beans.factory.support.RootBeanDefinition;
53-
import org.springframework.core.BridgeMethodResolver;
5455
import org.springframework.core.GenericTypeResolver;
5556
import org.springframework.core.MethodParameter;
5657
import org.springframework.core.Ordered;
@@ -342,7 +343,10 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
342343
}
343344
}
344345
for (Method method : targetClass.getDeclaredMethods()) {
345-
Annotation annotation = findAutowiredAnnotation(method);
346+
Method bridgedMethod = findBridgedMethod(method);
347+
Annotation annotation = isJava6VisibilityBridgeMethodPair(method, bridgedMethod) ?
348+
findAutowiredAnnotation(bridgedMethod) :
349+
findAutowiredAnnotation(method);
346350
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
347351
if (Modifier.isStatic(method.getModifiers())) {
348352
if (logger.isWarnEnabled()) {
@@ -370,9 +374,6 @@ private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
370374

371375
private Annotation findAutowiredAnnotation(AccessibleObject ao) {
372376
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
373-
if (ao instanceof Method) {
374-
ao = BridgeMethodResolver.findBridgedMethod((Method) ao);
375-
}
376377
Annotation annotation = ao.getAnnotation(type);
377378
if (annotation != null) {
378379
return annotation;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.beans.factory.annotation;
18+
19+
import static org.junit.Assert.assertNotNull;
20+
21+
import javax.inject.Inject;
22+
import javax.inject.Named;
23+
24+
import org.junit.Test;
25+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
26+
import org.springframework.stereotype.Component;
27+
28+
public class BridgeMethodAutowiringTests {
29+
30+
@Test
31+
public void SPR_8434() {
32+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
33+
ctx.register(UserServiceImpl.class, Foo.class);
34+
ctx.refresh();
35+
assertNotNull(ctx.getBean(UserServiceImpl.class).object);
36+
}
37+
38+
}
39+
40+
41+
abstract class GenericServiceImpl<D extends Object> {
42+
43+
public abstract void setObject(D object);
44+
45+
}
46+
47+
48+
class UserServiceImpl extends GenericServiceImpl<Foo> {
49+
50+
protected Foo object;
51+
52+
@Inject
53+
@Named("userObject")
54+
public void setObject(Foo object) {
55+
this.object = object;
56+
}
57+
}
58+
59+
@Component("userObject")
60+
class Foo { }
61+

org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import java.util.Map;
2727

28+
import org.springframework.util.Assert;
2829
import org.springframework.util.ClassUtils;
2930
import org.springframework.util.ReflectionUtils;
3031

@@ -210,4 +211,22 @@ private static Method searchForMatch(Class type, Method bridgeMethod) {
210211
return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
211212
}
212213

214+
/**
215+
* Compare the signatures of the bridge method and the method which it bridges. If
216+
* the parameter and return types are the same, it is a 'visibility' bridge method
217+
* introduced in Java 6 to fix http://bugs.sun.com/view_bug.do?bug_id=6342411.
218+
* See also http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html
219+
* @return whether signatures match as described
220+
*/
221+
public static boolean isJava6VisibilityBridgeMethodPair(Method bridgeMethod, Method bridgedMethod) {
222+
Assert.isTrue(bridgeMethod != null);
223+
Assert.isTrue(bridgedMethod != null);
224+
if (bridgeMethod == bridgedMethod) {
225+
return true;
226+
}
227+
return Arrays.equals(bridgeMethod.getParameterTypes(), bridgedMethod.getParameterTypes())
228+
&& bridgeMethod.getReturnType().equals(bridgedMethod.getReturnType());
229+
}
230+
231+
213232
}

0 commit comments

Comments
 (0)