DATACMNS-981 - Consider merged annotations when populating for annotation cache.
We now consider property annotations as merged annotations when initially scanning for annotations in a property declaration. Composed annotations such as declared outside our code are captured correctly because they use an own type that is not queried by users of PersistentProperty. Own, revised annotations, using @AliasFor providing an alias for annotation values require merged annotation processing.
Previously, annotations were cached as-is without resolving @AliasFor. This caused a later lookup via findAnnotation(…) to return the cached annotation without aliasing. Because the annotation was cached, no further lookup via AnnotatedElementUtils.findMergedAnnotation(…) was attempted.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { FIELD, METHOD })
public @interface RevisedAnnnotationWithAliasFor {
@AliasFor("value")
String name() default "";
@AliasFor("name")
String value() default "";
}
public class Person {
@RevisedAnnnotationWithAliasFor(value = "spring")
String firstname;
}
PersistentProperty firstname = …
property.findAnnotation(…) returned previously @RevisedAnnnotationWithAliasFor(value = "spring", name = "")
now we return @RevisedAnnnotationWithAliasFor(value = "spring", name = "spring")
This commit is contained in:
committed by
Oliver Gierke
parent
bab5ddade9
commit
2da5acc553
@@ -29,6 +29,7 @@ import javax.annotation.Nullable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.AccessType;
|
||||
@@ -42,7 +43,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AnnotationBasedPersistentProperty}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@@ -223,6 +224,17 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATACMNS-867
|
||||
public void revisedAnnotationWithAliasShouldHaveSynthesizedAttributeValues() {
|
||||
|
||||
assertThat(entity.getPersistentProperty("setter")).hasValueSatisfying(property -> {
|
||||
assertThat(property.findAnnotation(RevisedAnnnotationWithAliasFor.class)).hasValueSatisfying(annotation -> {
|
||||
assertThat(annotation.name()).isEqualTo("my-value");
|
||||
assertThat(annotation.value()).isEqualTo("my-value");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Class<? extends Annotation>, Annotation> getAnnotationCache(SamplePersistentProperty property) {
|
||||
return (Map<Class<? extends Annotation>, Annotation>) ReflectionTestUtils.getField(property, "annotationCache");
|
||||
@@ -248,7 +260,7 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
|
||||
@MyAnnotation String field;
|
||||
String getter;
|
||||
String setter;
|
||||
@RevisedAnnnotationWithAliasFor(value = "my-value") String setter;
|
||||
String doubleMapping;
|
||||
|
||||
@MyAnnotationAsMeta String meta;
|
||||
@@ -310,30 +322,41 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { FIELD, METHOD, ANNOTATION_TYPE })
|
||||
public static @interface MyAnnotation {
|
||||
public @interface MyAnnotation {
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { FIELD, METHOD })
|
||||
@MyAnnotation
|
||||
public static @interface MyAnnotationAsMeta {
|
||||
public @interface MyAnnotationAsMeta {
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { FIELD, METHOD })
|
||||
@MyAnnotation
|
||||
public static @interface MyComposedAnnotationUsingAliasFor {
|
||||
public @interface MyComposedAnnotationUsingAliasFor {
|
||||
|
||||
@AliasFor(annotation = MyAnnotation.class, attribute = "value")
|
||||
String name() default "spring";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { FIELD, METHOD })
|
||||
@interface RevisedAnnnotationWithAliasFor {
|
||||
|
||||
@AliasFor("value")
|
||||
String name() default "";
|
||||
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value = { FIELD, METHOD, ANNOTATION_TYPE })
|
||||
@Id
|
||||
public static @interface MyId {
|
||||
public @interface MyId {
|
||||
}
|
||||
|
||||
static class FieldAccess {
|
||||
@@ -380,7 +403,7 @@ public class AnnotationBasedPersistentPropertyUnitTests<P extends AnnotationBase
|
||||
@ReadOnlyProperty
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(FIELD)
|
||||
static @interface CustomReadOnly {
|
||||
@interface CustomReadOnly {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user