@Autowired, @Value and qualifiers may be used as meta-annotations for custom injection annotations
This commit is contained in:
parent
985cb9df11
commit
914a1b2088
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
@ -174,8 +174,31 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
|||
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
|
||||
for (Annotation annotation : annotationsToSearch) {
|
||||
Class<? extends Annotation> type = annotation.annotationType();
|
||||
boolean checkMeta = true;
|
||||
boolean fallbackToMeta = false;
|
||||
if (isQualifier(type)) {
|
||||
if (!checkQualifier(bdHolder, annotation, typeConverter)) {
|
||||
fallbackToMeta = true;
|
||||
}
|
||||
else {
|
||||
checkMeta = false;
|
||||
}
|
||||
}
|
||||
if (checkMeta) {
|
||||
boolean foundMeta = false;
|
||||
for (Annotation metaAnn : type.getAnnotations()) {
|
||||
Class<? extends Annotation> metaType = metaAnn.annotationType();
|
||||
if (isQualifier(metaType)) {
|
||||
foundMeta = true;
|
||||
// Only accept fallback match if @Qualifier annotation has a value...
|
||||
// Otherwise it is just a marker for a custom qualifier annotation.
|
||||
if ((fallbackToMeta && AnnotationUtils.getValue(metaAnn) == null) ||
|
||||
!checkQualifier(bdHolder, metaAnn, typeConverter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fallbackToMeta && !foundMeta) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -210,18 +233,18 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
|||
if (qualifier == null) {
|
||||
Annotation targetAnnotation = null;
|
||||
if (bd.getResolvedFactoryMethod() != null) {
|
||||
targetAnnotation = bd.getResolvedFactoryMethod().getAnnotation(type);
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
// look for matching annotation on the target class
|
||||
if (this.beanFactory != null) {
|
||||
Class<?> beanType = this.beanFactory.getType(bdHolder.getBeanName());
|
||||
if (beanType != null) {
|
||||
targetAnnotation = ClassUtils.getUserClass(beanType).getAnnotation(type);
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type);
|
||||
}
|
||||
}
|
||||
if (targetAnnotation == null && bd.hasBeanClass()) {
|
||||
targetAnnotation = ClassUtils.getUserClass(bd.getBeanClass()).getAnnotation(type);
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(bd.getBeanClass()), type);
|
||||
}
|
||||
}
|
||||
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
|
||||
|
@ -286,14 +309,27 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
|||
protected Object findValue(Annotation[] annotationsToSearch) {
|
||||
for (Annotation annotation : annotationsToSearch) {
|
||||
if (this.valueAnnotationType.isInstance(annotation)) {
|
||||
Object value = AnnotationUtils.getValue(annotation);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Value annotation must have a value attribute");
|
||||
}
|
||||
return value;
|
||||
return extractValue(annotation);
|
||||
}
|
||||
}
|
||||
for (Annotation annotation : annotationsToSearch) {
|
||||
Annotation metaAnn = annotation.annotationType().getAnnotation(this.valueAnnotationType);
|
||||
if (metaAnn != null) {
|
||||
return extractValue(metaAnn);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the value attribute from the given annotation.
|
||||
*/
|
||||
protected Object extractValue(Annotation valueAnnotation) {
|
||||
Object value = AnnotationUtils.getValue(valueAnnotation);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Value annotation must have a value attribute");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
@ -21,7 +21,6 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.scope.ScopedProxyUtils;
|
||||
|
@ -35,6 +34,8 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
|||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests for handling {@link Qualifier} annotations.
|
||||
*
|
||||
|
@ -279,7 +280,7 @@ public class QualifierAnnotationAutowireContextTests {
|
|||
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
|
||||
context.registerBeanDefinition(JUERGEN, person1);
|
||||
context.registerBeanDefinition(MARK, person2);
|
||||
context.registerBeanDefinition("autowired",
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(QualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
context.refresh();
|
||||
|
@ -287,6 +288,26 @@ public class QualifierAnnotationAutowireContextTests {
|
|||
assertEquals(JUERGEN, bean.getPerson().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutowiredFieldResolvesMetaQualifiedCandidate() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
ConstructorArgumentValues cavs1 = new ConstructorArgumentValues();
|
||||
cavs1.addGenericArgumentValue(JUERGEN);
|
||||
RootBeanDefinition person1 = new RootBeanDefinition(Person.class, cavs1, null);
|
||||
person1.addQualifier(new AutowireCandidateQualifier(TestQualifier.class));
|
||||
ConstructorArgumentValues cavs2 = new ConstructorArgumentValues();
|
||||
cavs2.addGenericArgumentValue(MARK);
|
||||
RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null);
|
||||
context.registerBeanDefinition(JUERGEN, person1);
|
||||
context.registerBeanDefinition(MARK, person2);
|
||||
context.registerBeanDefinition("autowired",
|
||||
new RootBeanDefinition(MetaQualifiedFieldTestBean.class));
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
context.refresh();
|
||||
MetaQualifiedFieldTestBean bean = (MetaQualifiedFieldTestBean) context.getBean("autowired");
|
||||
assertEquals(JUERGEN, bean.getPerson().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAutowiredMethodParameterResolvesQualifiedCandidate() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
|
@ -596,6 +617,24 @@ public class QualifierAnnotationAutowireContextTests {
|
|||
}
|
||||
|
||||
|
||||
private static class MetaQualifiedFieldTestBean {
|
||||
|
||||
@MyAutowired
|
||||
private Person person;
|
||||
|
||||
public Person getPerson() {
|
||||
return this.person;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
@TestQualifier
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface MyAutowired {
|
||||
}
|
||||
|
||||
|
||||
private static class QualifiedMethodParameterTestBean {
|
||||
|
||||
private Person person;
|
||||
|
@ -706,7 +745,6 @@ public class QualifierAnnotationAutowireContextTests {
|
|||
}
|
||||
|
||||
|
||||
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Qualifier
|
||||
public static @interface TestQualifier {
|
||||
|
|
|
@ -1,52 +1,117 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.context.annotation.configuration;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Test;
|
||||
import test.beans.TestBean;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import test.beans.TestBean;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests proving that @Qualifier annotations work when used
|
||||
* with @Configuration classes on @Bean methods.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class BeanMethodQualificationTests {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ApplicationContext ctx =
|
||||
new AnnotationConfigApplicationContext(Config.class, Pojo.class);
|
||||
Pojo pojo = ctx.getBean(Pojo.class);
|
||||
public void testStandard() {
|
||||
AnnotationConfigApplicationContext ctx =
|
||||
new AnnotationConfigApplicationContext(StandardConfig.class, StandardPojo.class);
|
||||
assertFalse(ctx.getBeanFactory().containsSingleton("testBean1"));
|
||||
StandardPojo pojo = ctx.getBean(StandardPojo.class);
|
||||
assertThat(pojo.testBean.getName(), equalTo("interesting"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCustom() {
|
||||
AnnotationConfigApplicationContext ctx =
|
||||
new AnnotationConfigApplicationContext(CustomConfig.class, CustomPojo.class);
|
||||
assertFalse(ctx.getBeanFactory().containsSingleton("testBean1"));
|
||||
CustomPojo pojo = ctx.getBean(CustomPojo.class);
|
||||
assertThat(pojo.testBean.getName(), equalTo("interesting"));
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
@Bean
|
||||
@Qualifier("interesting")
|
||||
static class StandardConfig {
|
||||
@Bean @Lazy @Qualifier("interesting")
|
||||
public TestBean testBean1() {
|
||||
return new TestBean("interesting");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Qualifier("boring")
|
||||
@Bean @Qualifier("boring")
|
||||
public TestBean testBean2() {
|
||||
return new TestBean("boring");
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
static class Pojo {
|
||||
|
||||
@Component @Lazy
|
||||
static class StandardPojo {
|
||||
@Autowired @Qualifier("interesting") TestBean testBean;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CustomConfig {
|
||||
@InterestingBean
|
||||
public TestBean testBean1() {
|
||||
return new TestBean("interesting");
|
||||
}
|
||||
|
||||
@Bean @Qualifier("boring")
|
||||
public TestBean testBean2() {
|
||||
return new TestBean("boring");
|
||||
}
|
||||
}
|
||||
|
||||
@InterestingPojo
|
||||
static class CustomPojo {
|
||||
@InterestingNeed TestBean testBean;
|
||||
}
|
||||
|
||||
@Bean @Lazy @Qualifier("interesting")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InterestingBean {
|
||||
}
|
||||
|
||||
@Autowired @Qualifier("interesting")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InterestingNeed {
|
||||
}
|
||||
|
||||
@Component @Lazy
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InterestingPojo {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue