Browse Source

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
pull/1170/merge
Stephane Nicoll 9 years ago
parent
commit
2b0bf9f04a
  1. 15
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
  2. 20
      spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java
  3. 38
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
  4. 4
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java

15
spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java

@ -17,6 +17,7 @@ @@ -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; @@ -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 @@ -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 @@ -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);

20
spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java

@ -16,6 +16,7 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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.
*/

38
spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

@ -63,6 +63,7 @@ import org.springframework.tests.sample.beans.ITestBean; @@ -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 { @@ -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 { @@ -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 { @@ -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();

4
spring-beans/src/test/java/org/springframework/beans/factory/support/BeanDefinitionTests.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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…
Cancel
Save