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");
}