@Autowired

1
2
3
4
5
6
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

@Autowired has a boolean argument called required with a default value of true. It tunes Spring’s behavior when it doesn’t find a suitable bean to wire. When true, an exception is thrown, otherwise, nothing is wired.

@AliasFor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AliasFor {
    @AliasFor("attribute")
    String value() default "";

    @AliasFor("value")
    String attribute() default "";

    Class<? extends Annotation> annotation() default Annotation.class;
}

Importantly, we can use this annotation implicitly as well as explicitly. Implicit usage is only restricted to aliases within an annotation. In comparison, explicit usage can also be made for an attribute in a meta-annotation.

Explicit Aliases Within an Annotation

@ComponentScan:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};
...
}

As we can see, value is defined here explicitly as an alias for basePackages, and vice-versa. This means we can use them interchangeably.

So effectively, these two usages are similar:

1
2
3
@ComponentScan(basePackages = "com.baeldung.aliasfor")

@ComponentScan(value = "com.baeldung.aliasfor")

Furthermore, since the two attributes are also marked as default, let’s write this more concisely:

1
@ComponentScan("com.baeldung.aliasfor")

Also, there’re a few implementation requirements that Spring mandates for this scenario. First, the aliased attributes should declare the same default value. Additionally, they should have the same return type. If we violate any of these constraints, the framework throws an AnnotationConfigurationException.

Explicit Aliases for Attribute in Meta-Annotation

First, let’s consider the framework annotation RequestMapping as our meta-annotation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";
    
    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};
    ...
}

Next, we’ll create a composed annotation MyMapping from it:

1
2
3
4
5
6
7
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
public @interface MyMapping {
    @AliasFor(annotation = RequestMapping.class, attribute = "method")
    RequestMethod[] action() default {};
}

As we can see, in @MyMapping, action is an explicit alias for the attribute method in @RequestMapping. That is, action in our composed annotation overrides the method in the meta-annotation.

Similar to aliases within an annotation, meta-annotation attribute aliases must also have the same return type. For example, RequestMethod[] in our case. Furthermore, the attribute annotation should reference the meta-annotation as in our usage of annotation = RequestMapping.class.

To demonstrate, let’s add a controller class called MyMappingController. We’ll decorate its method with our custom annotation.

Specifically, here we’ll add only two attributes to @MyMapping, route, and action:

1
2
3
4
5
6
7
@Controller
public class MyMappingController {

    @MyMapping(action = RequestMethod.PATCH, route = "/test")
    public void mappingMethod() {}
    
}

Finally, to see how explicit aliases behave, let’s add a simple test:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Test
public void givenComposedAnnotation_whenExplicitAlias_thenMetaAnnotationAttributeOverridden() {
    for (Method method : controllerClass.getMethods()) {
        if (method.isAnnotationPresent(MyMapping.class)) {
            MyMapping annotation = AnnotationUtils.findAnnotation(method, MyMapping.class);
            RequestMapping metaAnnotation = 
              AnnotationUtils.findAnnotation(method, RequestMapping.class);

            assertEquals(RequestMethod.PATCH, annotation.action()[0]);

            assertEquals(0, metaAnnotation.method().length);
        }
    }
}

As we can see, our custom annotation’s attribute action has overridden the meta-annotation @RequestMapping‘s attribute method.

@AliasFor注解示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

    boolean proxyBeanMethods() default true;
}
```

参考文章:Spring Core Annotations