Browse Source

@Value can be used as aliased meta-annotation

Issue: SPR-13603
pull/946/head
Juergen Hoeller 9 years ago
parent
commit
4f955932a7
  1. 23
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
  2. 84
      spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java
  3. 29
      spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -32,6 +32,8 @@ import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver; import org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -315,25 +317,20 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
* Determine a suggested value from any of the given candidate annotations. * Determine a suggested value from any of the given candidate annotations.
*/ */
protected Object findValue(Annotation[] annotationsToSearch) { protected Object findValue(Annotation[] annotationsToSearch) {
for (Annotation annotation : annotationsToSearch) { AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
if (this.valueAnnotationType.isInstance(annotation)) { AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
return extractValue(annotation); if (attr != null) {
} return extractValue(attr);
}
for (Annotation annotation : annotationsToSearch) {
Annotation metaAnn = annotation.annotationType().getAnnotation(this.valueAnnotationType);
if (metaAnn != null) {
return extractValue(metaAnn);
}
} }
return null; return null;
} }
/** /**
* Extract the value attribute from the given annotation. * Extract the value attribute from the given annotation.
* @since 4.3
*/ */
protected Object extractValue(Annotation valueAnnotation) { protected Object extractValue(AnnotationAttributes attr) {
Object value = AnnotationUtils.getValue(valueAnnotation); Object value = attr.get(AnnotationUtils.VALUE);
if (value == null) { if (value == null) {
throw new IllegalStateException("Value annotation must have a value attribute"); throw new IllegalStateException("Value annotation must have a value attribute");
} }

84
spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java

@ -17,6 +17,8 @@
package org.springframework.context.annotation.configuration; package org.springframework.context.annotation.configuration;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import javax.inject.Provider; import javax.inject.Provider;
@ -35,6 +37,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.tests.sample.beans.Colour; import org.springframework.tests.sample.beans.Colour;
@ -119,6 +122,20 @@ public class AutowiredConfigurationTests {
doTestValueInjection(context); doTestValueInjection(context);
} }
@Test
public void testValueInjectionWithMetaAnnotation() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ValueConfigWithMetaAnnotation.class);
doTestValueInjection(context);
}
@Test
public void testValueInjectionWithAliasedMetaAnnotation() {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ValueConfigWithAliasedMetaAnnotation.class);
doTestValueInjection(context);
}
@Test @Test
public void testValueInjectionWithProviderFields() { public void testValueInjectionWithProviderFields() {
AnnotationConfigApplicationContext context = AnnotationConfigApplicationContext context =
@ -291,6 +308,73 @@ public class AutowiredConfigurationTests {
} }
@Value("#{systemProperties[myProp]}")
@Retention(RetentionPolicy.RUNTIME)
public @interface MyProp {
}
@Configuration
@Scope("prototype")
static class ValueConfigWithMetaAnnotation {
@MyProp
private String name;
private String name2;
@MyProp
public void setName2(String name) {
this.name2 = name;
}
@Bean @Scope("prototype")
public TestBean testBean() {
return new TestBean(name);
}
@Bean @Scope("prototype")
public TestBean testBean2() {
return new TestBean(name2);
}
}
@Value("")
@Retention(RetentionPolicy.RUNTIME)
public @interface AliasedProp {
@AliasFor(annotation = Value.class)
String value();
}
@Configuration
@Scope("prototype")
static class ValueConfigWithAliasedMetaAnnotation {
@AliasedProp("#{systemProperties[myProp]}")
private String name;
private String name2;
@AliasedProp("#{systemProperties[myProp]}")
public void setName2(String name) {
this.name2 = name;
}
@Bean @Scope("prototype")
public TestBean testBean() {
return new TestBean(name);
}
@Bean @Scope("prototype")
public TestBean testBean2() {
return new TestBean(name2);
}
}
@Configuration @Configuration
static class ValueConfigWithProviderFields { static class ValueConfigWithProviderFields {

29
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

@ -97,6 +97,35 @@ public class AnnotatedElementUtils {
private static final Boolean CONTINUE = null; private static final Boolean CONTINUE = null;
/**
* Build an adapted {@link AnnotatedElement} for the given annotations,
* typically for use with other methods on {@link AnnotatedElementUtils}.
* @param annotations the annotations to expose through the {@code AnnotatedElement}
* @since 4.3
*/
public static AnnotatedElement forAnnotations(final Annotation... annotations) {
return new AnnotatedElement() {
@Override
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
for (Annotation ann : annotations) {
if (ann.annotationType() == annotationClass) {
return (T) ann;
}
}
return null;
}
@Override
public Annotation[] getAnnotations() {
return annotations;
}
@Override
public Annotation[] getDeclaredAnnotations() {
return annotations;
}
};
}
/** /**
* Get the fully qualified class names of all meta-annotation types * Get the fully qualified class names of all meta-annotation types
* <em>present</em> on the annotation (of the specified {@code annotationType}) * <em>present</em> on the annotation (of the specified {@code annotationType})

Loading…
Cancel
Save