From 41ddda4a15da42b08883949d9767cb6cc6a8c743 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Apr 2016 17:25:58 +0100 Subject: [PATCH] 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 --- .../properties/AnnotationsPropertySource.java | 26 ++++++++++---- .../AnnotationsPropertySourceTests.java | 34 +++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java index 86d6c7617e..9101523583 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySource.java @@ -18,12 +18,15 @@ package org.springframework.boot.test.autoconfigure.properties; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.util.ObjectUtils; @@ -55,28 +58,39 @@ public class AnnotationsPropertySource extends EnumerablePropertySource private Map getProperties(Class source) { Map properties = new LinkedHashMap(); - collectProperties(source, properties); + collectProperties(source, source, properties); return Collections.unmodifiableMap(properties); } - private void collectProperties(Class source, Map properties) { + private void collectProperties(Class root, Class source, + Map properties) { if (source != null) { - for (Annotation annotation : AnnotationUtils.getAnnotations(source)) { + for (Annotation annotation : getMergedAnnotations(root, source)) { if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) { - annotation.annotationType().getAnnotation(PropertyMapping.class); PropertyMapping typeMapping = annotation.annotationType() .getAnnotation(PropertyMapping.class); for (Method attribute : annotation.annotationType() .getDeclaredMethods()) { 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 getMergedAnnotations(Class root, Class source) { + List mergedAnnotations = new ArrayList(); + 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, PropertyMapping typeMapping, Map properties) { PropertyMapping attributeMapping = AnnotationUtils.getAnnotation(attribute, diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java index 3d6cd38137..1be861be05 100644 --- a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/properties/AnnotationsPropertySourceTests.java @@ -23,6 +23,8 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.core.annotation.AliasFor; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -154,6 +156,14 @@ public class AnnotationsPropertySourceTests { 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 { } @@ -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"; + + } + }