Browse Source

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
pull/7/head
Chris Beams 13 years ago
parent
commit
980c15d578
  1. 13
      org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
  2. 61
      org.springframework.context/src/test/java/org/springframework/beans/factory/annotation/BridgeMethodAutowiringTests.java
  3. 19
      org.springframework.core/src/main/java/org/springframework/core/BridgeMethodResolver.java

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

@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
package org.springframework.beans.factory.annotation;
import static org.springframework.core.BridgeMethodResolver.findBridgedMethod;
import static org.springframework.core.BridgeMethodResolver.isJava6VisibilityBridgeMethodPair;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
@ -35,7 +38,6 @@ import java.util.concurrent.ConcurrentHashMap; @@ -35,7 +38,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
@ -50,7 +52,6 @@ import org.springframework.beans.factory.config.InstantiationAwareBeanPostProces @@ -50,7 +52,6 @@ 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;
@ -342,7 +343,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean @@ -342,7 +343,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
}
for (Method method : targetClass.getDeclaredMethods()) {
Annotation annotation = findAutowiredAnnotation(method);
Method bridgedMethod = findBridgedMethod(method);
Annotation annotation = isJava6VisibilityBridgeMethodPair(method, bridgedMethod) ?
findAutowiredAnnotation(bridgedMethod) :
findAutowiredAnnotation(method);
if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
@ -370,9 +374,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean @@ -370,9 +374,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private Annotation findAutowiredAnnotation(AccessibleObject ao) {
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
if (ao instanceof Method) {
ao = BridgeMethodResolver.findBridgedMethod((Method) ao);
}
Annotation annotation = ao.getAnnotation(type);
if (annotation != null) {
return annotation;

61
org.springframework.context/src/test/java/org/springframework/beans/factory/annotation/BridgeMethodAutowiringTests.java

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/*
* 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.
* 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.beans.factory.annotation;
import static org.junit.Assert.assertNotNull;
import javax.inject.Inject;
import javax.inject.Named;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
public class BridgeMethodAutowiringTests {
@Test
public void SPR_8434() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(UserServiceImpl.class, Foo.class);
ctx.refresh();
assertNotNull(ctx.getBean(UserServiceImpl.class).object);
}
}
abstract class GenericServiceImpl<D extends Object> {
public abstract void setObject(D object);
}
class UserServiceImpl extends GenericServiceImpl<Foo> {
protected Foo object;
@Inject
@Named("userObject")
public void setObject(Foo object) {
this.object = object;
}
}
@Component("userObject")
class Foo { }

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

@ -25,6 +25,7 @@ import java.util.Arrays; @@ -25,6 +25,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@ -210,4 +211,22 @@ public abstract class BridgeMethodResolver { @@ -210,4 +211,22 @@ public abstract class BridgeMethodResolver {
return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
}
/**
* Compare the signatures of the bridge method and the method which it bridges. If
* the parameter and return types are the same, it is a 'visibility' bridge method
* introduced in Java 6 to fix http://bugs.sun.com/view_bug.do?bug_id=6342411.
* See also http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html
* @return whether signatures match as described
*/
public static boolean isJava6VisibilityBridgeMethodPair(Method bridgeMethod, Method bridgedMethod) {
Assert.isTrue(bridgeMethod != null);
Assert.isTrue(bridgedMethod != null);
if (bridgeMethod == bridgedMethod) {
return true;
}
return Arrays.equals(bridgeMethod.getParameterTypes(), bridgedMethod.getParameterTypes())
&& bridgeMethod.getReturnType().equals(bridgedMethod.getReturnType());
}
}

Loading…
Cancel
Save