Support the use of @AliasFor with @PropertyMapping

Previously, when @AliasFor was used, the value of the mapped property
would be incorrect as the value of the canonical attribute would be
used, rather than the value of the alias.

This commit updates AnnotationsPropertySource to use a merged annotation
as the source of attribute values, thereby ensuring that any aliased
attributes are configured correctly.

Closes gh-5821
pull/5816/merge
Andy Wilkinson 9 years ago
parent f468aff47f
commit 41ddda4a15

@ -18,12 +18,15 @@ package org.springframework.boot.test.autoconfigure.properties;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
@ -55,26 +58,37 @@ public class AnnotationsPropertySource extends EnumerablePropertySource<Class<?>
private Map<String, Object> getProperties(Class<?> source) { private Map<String, Object> getProperties(Class<?> source) {
Map<String, Object> properties = new LinkedHashMap<String, Object>(); Map<String, Object> properties = new LinkedHashMap<String, Object>();
collectProperties(source, properties); collectProperties(source, source, properties);
return Collections.unmodifiableMap(properties); return Collections.unmodifiableMap(properties);
} }
private void collectProperties(Class<?> source, Map<String, Object> properties) { private void collectProperties(Class<?> root, Class<?> source,
Map<String, Object> properties) {
if (source != null) { if (source != null) {
for (Annotation annotation : AnnotationUtils.getAnnotations(source)) { for (Annotation annotation : getMergedAnnotations(root, source)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) { if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
annotation.annotationType().getAnnotation(PropertyMapping.class);
PropertyMapping typeMapping = annotation.annotationType() PropertyMapping typeMapping = annotation.annotationType()
.getAnnotation(PropertyMapping.class); .getAnnotation(PropertyMapping.class);
for (Method attribute : annotation.annotationType() for (Method attribute : annotation.annotationType()
.getDeclaredMethods()) { .getDeclaredMethods()) {
collectProperties(annotation, attribute, typeMapping, properties); collectProperties(annotation, attribute, typeMapping, properties);
} }
collectProperties(annotation.annotationType(), properties); collectProperties(root, annotation.annotationType(), properties);
} }
} }
collectProperties(source.getSuperclass(), properties); collectProperties(root, source.getSuperclass(), properties);
}
}
private List<Annotation> getMergedAnnotations(Class<?> root, Class<?> source) {
List<Annotation> mergedAnnotations = new ArrayList<Annotation>();
for (Annotation annotation : AnnotationUtils.getAnnotations(source)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
mergedAnnotations.add(AnnotatedElementUtils.getMergedAnnotation(root,
annotation.annotationType()));
}
} }
return mergedAnnotations;
} }
private void collectProperties(Annotation annotation, Method attribute, private void collectProperties(Annotation annotation, Method attribute,

@ -23,6 +23,8 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.core.annotation.AliasFor;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
@ -154,6 +156,14 @@ public class AnnotationsPropertySourceTests {
assertThat(source.getProperty("test.example")).isEqualTo("charlie"); assertThat(source.getProperty("test.example")).isEqualTo("charlie");
} }
@Test
public void propertyMappedAttributesCanBeAliased() {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertyMappedAttributeWithAnAlias.class);
assertThat(source.getPropertyNames()).containsExactly("aliasing.value");
assertThat(source.getProperty("aliasing.value")).isEqualTo("baz");
}
static class NoAnnotation { static class NoAnnotation {
} }
@ -307,4 +317,28 @@ public class AnnotationsPropertySourceTests {
} }
@AttributeWithAliasAnnotation("baz")
static class PropertyMappedAttributeWithAnAlias {
}
@Retention(RetentionPolicy.RUNTIME)
@AliasedAttributeAnnotation
static @interface AttributeWithAliasAnnotation {
@AliasFor(annotation = AliasedAttributeAnnotation.class, attribute = "value")
String value() default "foo";
String someOtherAttribute() default "shouldNotBeMapped";
}
@Retention(RetentionPolicy.RUNTIME)
@PropertyMapping("aliasing")
static @interface AliasedAttributeAnnotation {
String value() default "bar";
}
} }

Loading…
Cancel
Save