@Bean processing explicitly ignores bridge methods (for method overrides with return type narrowing on JDK 8)
Issue: SPR-11718
(cherry picked from commit 656fc52
)
This commit is contained in:
parent
1f630a5fb9
commit
310bdbcb15
|
@ -23,6 +23,7 @@ import org.junit.Test;
|
|||
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
|
||||
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -55,6 +56,39 @@ public class BeanMethodPolymorphismTests {
|
|||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingOnASM() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(OverridingConfig.class.getName()));
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingWithNarrowedReturnType() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.register(NarrowedOverridingConfig.class);
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverridingWithNarrowedReturnTypeOnASM() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
ctx.registerBeanDefinition("config", new RootBeanDefinition(NarrowedOverridingConfig.class.getName()));
|
||||
ctx.setAllowBeanDefinitionOverriding(false);
|
||||
ctx.refresh();
|
||||
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
|
||||
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodOverloadingWithoutInheritance() {
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
|
@ -173,6 +207,26 @@ public class BeanMethodPolymorphismTests {
|
|||
}
|
||||
|
||||
|
||||
static class ExtendedTestBean extends TestBean {
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class NarrowedOverridingConfig extends BaseConfig {
|
||||
|
||||
@Bean @Lazy
|
||||
@Override
|
||||
public ExtendedTestBean testBean() {
|
||||
return new ExtendedTestBean() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "overridden";
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class ConfigWithOverloading {
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -128,7 +128,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
|||
public boolean hasAnnotatedMethods(String annotationType) {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
|||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||
for (Method method : methods) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
|
@ -57,8 +58,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
* to ensure that the hierarchical ordering of the entries is preserved.
|
||||
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes(LinkedMultiValueMap, String)
|
||||
*/
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(
|
||||
4);
|
||||
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
|
||||
|
||||
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
|
||||
|
||||
|
@ -70,6 +70,11 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
// Skip bridge methods - we're only interested in original annotation-defining user methods.
|
||||
// On JDK 8, we'd otherwise run into double detection of the same annotated method...
|
||||
if ((access & Opcodes.ACC_BRIDGE) != 0) {
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return new MethodMetadataReadingVisitor(name, access, getClassName(), this.classLoader, this.methodMetadataSet);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue