@Value can be used as aliased meta-annotation
Issue: SPR-13603
This commit is contained in:
parent
3242ad8fc4
commit
4f955932a7
|
@ -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");
|
||||
* 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.RootBeanDefinition;
|
||||
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.util.Assert;
|
||||
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.
|
||||
*/
|
||||
protected Object findValue(Annotation[] annotationsToSearch) {
|
||||
for (Annotation annotation : annotationsToSearch) {
|
||||
if (this.valueAnnotationType.isInstance(annotation)) {
|
||||
return extractValue(annotation);
|
||||
}
|
||||
}
|
||||
for (Annotation annotation : annotationsToSearch) {
|
||||
Annotation metaAnn = annotation.annotationType().getAnnotation(this.valueAnnotationType);
|
||||
if (metaAnn != null) {
|
||||
return extractValue(metaAnn);
|
||||
}
|
||||
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
|
||||
if (attr != null) {
|
||||
return extractValue(attr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the value attribute from the given annotation.
|
||||
* @since 4.3
|
||||
*/
|
||||
protected Object extractValue(Annotation valueAnnotation) {
|
||||
Object value = AnnotationUtils.getValue(valueAnnotation);
|
||||
protected Object extractValue(AnnotationAttributes attr) {
|
||||
Object value = attr.get(AnnotationUtils.VALUE);
|
||||
if (value == null) {
|
||||
throw new IllegalStateException("Value annotation must have a value attribute");
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.context.annotation.configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Provider;
|
||||
|
@ -35,6 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.tests.sample.beans.Colour;
|
||||
|
@ -119,6 +122,20 @@ public class AutowiredConfigurationTests {
|
|||
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
|
||||
public void testValueInjectionWithProviderFields() {
|
||||
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
|
||||
static class ValueConfigWithProviderFields {
|
||||
|
||||
|
|
|
@ -97,6 +97,35 @@ public class AnnotatedElementUtils {
|
|||
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
|
||||
* <em>present</em> on the annotation (of the specified {@code annotationType})
|
||||
|
|
Loading…
Reference in New Issue