Add Qualified element on RootBeanDefinition
Improve RootBeanDefinition to specify an AnnotatedElement that holds qualifier information. When such element is present, any qualifier that it defines will be used to find a matching candidate. Issue: SPR-14725
This commit is contained in:
parent
f24ce76edb
commit
2b0bf9f04a
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.beans.factory.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
@ -49,6 +50,7 @@ import org.springframework.util.StringUtils;
|
|||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.5
|
||||
* @see AutowireCandidateQualifier
|
||||
* @see Qualifier
|
||||
|
@ -225,8 +227,12 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
|||
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
|
||||
}
|
||||
if (qualifier == null) {
|
||||
// First, check annotation on factory method, if applicable
|
||||
Annotation targetAnnotation = getFactoryMethodAnnotation(bd, type);
|
||||
// First, check annotation on qualified element, if any
|
||||
Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type);
|
||||
// Then, check annotation on factory method, if applicable
|
||||
if (targetAnnotation == null) {
|
||||
targetAnnotation = getFactoryMethodAnnotation(bd, type);
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
|
||||
if (dbd != null) {
|
||||
|
@ -291,6 +297,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
|
|||
return true;
|
||||
}
|
||||
|
||||
protected Annotation getQualifiedElementAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
|
||||
AnnotatedElement qualifiedElement = bd.getQualifiedElement();
|
||||
return (qualifiedElement != null ? AnnotationUtils.getAnnotation(qualifiedElement, type) : null);
|
||||
}
|
||||
|
||||
protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
|
||||
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
|
||||
return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.beans.factory.support;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -58,6 +59,8 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
|||
|
||||
boolean isFactoryMethodUnique = false;
|
||||
|
||||
volatile AnnotatedElement qualifiedElement;
|
||||
|
||||
/** Package-visible field for caching the determined Class of a given bean definition */
|
||||
volatile Class<?> resolvedTargetType;
|
||||
|
||||
|
@ -182,6 +185,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
|||
this.allowCaching = original.allowCaching;
|
||||
this.targetType = original.targetType;
|
||||
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
|
||||
this.qualifiedElement = original.qualifiedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,6 +261,22 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
|
|||
this.isFactoryMethodUnique = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the {@link AnnotatedElement} defining qualifiers.
|
||||
* @since 4.3.3
|
||||
*/
|
||||
public void setQualifiedElement(AnnotatedElement qualifiedElement) {
|
||||
this.qualifiedElement = qualifiedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link AnnotatedElement} defining qualifiers, if any.
|
||||
* @since 4.3.3
|
||||
*/
|
||||
public AnnotatedElement getQualifiedElement() {
|
||||
return this.qualifiedElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given candidate qualifies as a factory method.
|
||||
*/
|
||||
|
|
|
@ -63,6 +63,7 @@ import org.springframework.tests.sample.beans.ITestBean;
|
|||
import org.springframework.tests.sample.beans.IndexedTestBean;
|
||||
import org.springframework.tests.sample.beans.NestedTestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -1026,14 +1027,35 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierInjectionBean.class));
|
||||
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
|
||||
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
|
||||
bf.registerBeanDefinition("testBean", bd);
|
||||
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
|
||||
bf.registerBeanDefinition("dependencyBean", bd);
|
||||
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||
assertSame(bf.getBean("dependencyBean"), bean.getTestBean());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testObjectFactoryQualifierProviderInjection() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(bf);
|
||||
bf.addBeanPostProcessor(bpp);
|
||||
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierInjectionBean.class));
|
||||
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
|
||||
bd.setQualifiedElement(ReflectionUtils.findMethod(getClass(), "testBeanQualifierProvider"));
|
||||
bf.registerBeanDefinition("dependencyBean", bd);
|
||||
bf.registerBeanDefinition("dependencyBean2", new RootBeanDefinition(TestBean.class));
|
||||
|
||||
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
|
||||
assertSame(bf.getBean("dependencyBean"), bean.getTestBean());
|
||||
bf.destroySingletons();
|
||||
}
|
||||
|
||||
@Qualifier("testBean")
|
||||
private void testBeanQualifierProvider() {}
|
||||
|
||||
@Test
|
||||
public void testObjectFactorySerialization() throws Exception {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
@ -1588,11 +1610,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Repository.class);
|
||||
bf.registerBeanDefinition("integerRepo", rbd);
|
||||
rbd.setQualifiedElement(ReflectionUtils.findField(getClass(), "integerRepositoryQualifierProvider"));
|
||||
bf.registerBeanDefinition("integerRepository", rbd); // Bean name not matching qualifier
|
||||
|
||||
RepositoryFieldInjectionBeanWithQualifiers bean = (RepositoryFieldInjectionBeanWithQualifiers) bf.getBean("annotatedBean");
|
||||
Repository<?> sr = bf.getBean("stringRepo", Repository.class);
|
||||
Repository<?> ir = bf.getBean("integerRepo", Repository.class);
|
||||
Repository<?> ir = bf.getBean("integerRepository", Repository.class);
|
||||
assertSame(sr, bean.stringRepository);
|
||||
assertSame(ir, bean.integerRepository);
|
||||
assertSame(1, bean.stringRepositoryArray.length);
|
||||
|
@ -1606,9 +1629,12 @@ public class AutowiredAnnotationBeanPostProcessorTests {
|
|||
assertSame(1, bean.stringRepositoryMap.size());
|
||||
assertSame(1, bean.integerRepositoryMap.size());
|
||||
assertSame(sr, bean.stringRepositoryMap.get("stringRepo"));
|
||||
assertSame(ir, bean.integerRepositoryMap.get("integerRepo"));
|
||||
assertSame(ir, bean.integerRepositoryMap.get("integerRepository"));
|
||||
}
|
||||
|
||||
@Qualifier("integerRepo")
|
||||
private Repository<?> integerRepositoryQualifierProvider;
|
||||
|
||||
@Test
|
||||
public void testGenericsBasedFieldInjectionWithSimpleMatch() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 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.
|
||||
|
@ -126,6 +126,7 @@ public class BeanDefinitionTests {
|
|||
bd.getConstructorArgumentValues().addIndexedArgumentValue(1, new Integer(5));
|
||||
bd.getPropertyValues().add("name", "myName");
|
||||
bd.getPropertyValues().add("age", "99");
|
||||
bd.setQualifiedElement(getClass());
|
||||
|
||||
GenericBeanDefinition childBd = new GenericBeanDefinition();
|
||||
childBd.setParentName("bd");
|
||||
|
@ -138,6 +139,7 @@ public class BeanDefinitionTests {
|
|||
|
||||
mergedBd.getConstructorArgumentValues().getArgumentValue(1, null).setValue(new Integer(9));
|
||||
assertEquals(new Integer(5), bd.getConstructorArgumentValues().getArgumentValue(1, null).getValue());
|
||||
assertEquals(getClass(), bd.getQualifiedElement());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue