Skip to content

@AliasFor doesn’t work on attribute in custom annotation

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?

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.