Consider meta-annotations when creating an AnnotationsPropertySource

Previously, meta-annotations were not considered when looking for
annotations that may have property mappings but were considered when
looking for a `@PropertyMapping` annotation. This led to three
problems:

1. Properties that should have been included in the property source
   were not included
2. Properties that were included may have had the wrong name
3. Properties were included when they should not have been

`@DataJpaTests` provided a concrete example of all three problems:

1. The `replace` and `connection` attributes from
   `@AutoConfigureTestDatabase` were not included in the property
   source
2. The `showSql` attribute from `@DataJpaTest` was mapped as
   `spring.test.database.spring.jpa.show-sql`
3. The `useDefaultFilters` attribute from `@DataJpaTest` was included
   in the property source.

This commit updates AnnotationsPropertySource to consider
meta-annotations when looking for attributes that should be mapped.
This addresses the first problem. Furthermore,
AnnotationsPropertySource has been updated to no longer consider
meta-annotations when looking for a type-level property mapping.
This addresses the second and third problems.

Closes gh-5794
This commit is contained in:
Andy Wilkinson 2016-04-28 14:00:42 +01:00
parent ebb0ff8638
commit 34b6915607
2 changed files with 51 additions and 3 deletions

View File

@ -35,6 +35,7 @@ import org.springframework.util.StringUtils;
* {@link PropertyMapping @PropertyMapping}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @since 1.4.0
*/
public class AnnotationsPropertySource extends EnumerablePropertySource<Class<?>> {
@ -60,14 +61,16 @@ public class AnnotationsPropertySource extends EnumerablePropertySource<Class<?>
private void collectProperties(Class<?> source, Map<String, Object> properties) {
if (source != null) {
for (Annotation annotation : source.getDeclaredAnnotations()) {
for (Annotation annotation : AnnotationUtils.getAnnotations(source)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
PropertyMapping typeMapping = AnnotationUtils.getAnnotation(
annotation.annotationType(), PropertyMapping.class);
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(source.getSuperclass(), properties);

View File

@ -29,6 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link AnnotationsPropertySource}.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class AnnotationsPropertySourceTests {
@ -133,6 +134,26 @@ public class AnnotationsPropertySourceTests {
assertThat(source.getPropertyNames()).contains("camel-case-to-kebab-case");
}
@Test
public void propertiesFromMetaAnnotationsAreMapped() throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertiesFromSingleMetaAnnotation.class);
assertThat(source.getPropertyNames()).containsExactly("value");
assertThat(source.getProperty("value")).isEqualTo("foo");
}
@Test
public void propertiesFromMultipleMetaAnnotationsAreMappedUsingTheirOwnPropertyMapping()
throws Exception {
AnnotationsPropertySource source = new AnnotationsPropertySource(
PropertiesFromMultipleMetaAnnotations.class);
assertThat(source.getPropertyNames()).containsExactly("value", "test.value",
"test.example");
assertThat(source.getProperty("value")).isEqualTo("alpha");
assertThat(source.getProperty("test.value")).isEqualTo("bravo");
assertThat(source.getProperty("test.example")).isEqualTo("charlie");
}
static class NoAnnotation {
}
@ -262,4 +283,28 @@ public class AnnotationsPropertySourceTests {
}
@PropertiesFromSingleMetaAnnotationAnnotation
static class PropertiesFromSingleMetaAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
@TypeLevelAnnotation("foo")
static @interface PropertiesFromSingleMetaAnnotationAnnotation {
}
@PropertiesFromMultipleMetaAnnotationsAnnotation
static class PropertiesFromMultipleMetaAnnotations {
}
@Retention(RetentionPolicy.RUNTIME)
@TypeLevelAnnotation("alpha")
@TypeLevelWithPrefixAnnotation("bravo")
@TypeAndAttributeLevelWithPrefixAnnotation("charlie")
static @interface PropertiesFromMultipleMetaAnnotationsAnnotation {
}
}