I’m using SpringBoot 2.4.2. And I’m struggling with @AliasFor with custom annotation.
I implemented below custom annotation.
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomAnnotation {
@AliasFor("aliasAttribute")
String value() default "";
@AliasFor("value")
String aliasAttribute() "";
}
And using it like this.
@CustomAnnoatation("test")
@Component
public class TestClass() {
// codes here
}
And this test code fails.
@SpringBootTest(classes = TestClass.class)
public class CustomAnnotationTest {
@Autowired
TestClass testClass;
@Test
public void valueTest1() {
Annotation annotation = testClass.getClass().getAnnotation(CustomAnnotation.class);
assertThat(((CustomAnnotation) annotation).value()).isEqualTo(((CustomAnnotation) annotation).aliasAttribute());
}
}
with message
org.opentest4j.AssertionFailedError: Expecting: <""> to be equal to: <"test">
I don’t know why, anyone know?
Advertisement
Answer
An annotation is static metadata for a class, field etc. so Spring cannot change anything about it. To make features as @AliasFor possible Spring uses, what they call, synthesized annotations. For those to be used/detected you need to utilize the Spring internals to obtain that synthesized annotation and for the @AliasFor to work. For this use AnnotationUtils.findAnnotation (Spring uses that internally as well).
@AliasFor is a Spring feature so without using the Spring components this won’t work.
Your test method is basically the same as
@Test
public void valueTest1() {
Annotation annotation = TestClass.class.getAnnotation(CustomAnnotation.class);
assertThat(((CustomAnnotation) annotation).value()).isEqualTo(((CustomAnnotation) annotation).aliasAttribute());
}
Both this test and your test will fail, because they simply don’t use the Spring infrastructure for detecting annotations and apply the features of Spring.
When using AnnotationUtils.findAnnotation the test will pass.
class CustomAnnotationTest {
@Test
void testStandardJava() {
CustomAnnotation annotation = TestClass.class.getAnnotation(CustomAnnotation.class);
assertThat(annotation.value()).isEqualTo(annotation.aliasAttribute());
}
@Test
void testWithSpring() {
CustomAnnotation annotation = AnnotationUtils.findAnnotation(TestClass.class, CustomAnnotation.class);
assertThat(annotation.value()).isEqualTo(annotation.aliasAttribute());
}
}
The testStandardJava will fail, the testWithSpring will pass because it uses the proper mechanisms.