There are couple of improvements made in the annotation mechanism in Java 8. These are:
- Repeatable annotations
- Type annotations
Code for this section is inside ch12 package.
Before Java 8, it was not possible to use same annotation twice at the same
location i.e. you can't use annotation @Foo
twice on a method. If you have
used JPA then you would have use an annotation called @JoinColumns
that allows
wraps multiple @JoinColumn
annotation as shown below.
@ManyToOne
@JoinColumns({
@JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
})
public Address getAddress() { return address; }
In Java 8, you can write the same as shown below because with Java 8 you can repeat an annotation multiple time at the same location.
@ManyToOne
@JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
public Address getAddress() { return address; }
With Java 8 you can use same annotation type multiple times possibly with different arguments at any location(class, method, field declaration) in your Java code.
To write your own repeatable annotation you have to do the following:
Step 1: Create an annotation with @Repeatable
annotation as shown below.
@Repeatable
annotation requires you to specify a mandatory value for the
container type that will contain the annotation. We will create container
annotation in step 2.
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(CreateVms.class)
public @interface CreateVm {
String name();
}
Step 2: Create a container annotation that holds the annotation.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface CreateVms {
CreateVm[] value();
}
Now you can use the annotation multiple times on any method as shown below.
@CreateVm(name = "vm1")
@CreateVm(name = "vm2")
public void manage() {
System.out.println("Managing ....");
}
If you have to find all the repeatable annotations on a method then you can use
getAnnotationsByType
method that is now available on java.lang.Class
and
java.lang.reflect.Method
. To print all the vm names, you can write code as
shown below.
CreateVm[] createVms = VmManager.class.getMethod("manage").getAnnotationsByType(CreateVm.class);
Stream.of(createVms).map(CreateVm::name).forEach(System.out::println);
You can now apply annotations at two more target locations -- TYPE_PARAMETER and TYPE_USE.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE_PARAMETER})
public @interface MyAnnotation {
}
You can use it like
class MyAnnotationUsage<@MyAnnotation T> {
}
You can also use annotations at type usage as shown below.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE_USE})
public @interface MyAnnotation {
}
Then you can use them as shown below.
public static void doSth() {
List<@MyAnnotation String> names = Arrays.asList("shekhar");
}