15. Annotations

15.1. Marker

1import java.lang.annotation.Retention;
2import java.lang.annotation.RetentionPolicy;
 1@Retention(RetentionPolicy.RUNTIME)
 2@interface OneOffCoder { }
 3
 4@OneOffCoder
 5public static class Car {
 6  private final String make, model;
 7  private final int year;
 8
 9  public Car(String make, String model, int year) {
10    this.make = make;
11    this.model = model;
12    this.year = year;
13  }
14
15  @OneOffCoder
16  @Override
17  public String toString() {
18    return (new StringBuilder())
19        .append(make)
20        .append(' ')
21        .append(model)
22        .append(' ')
23        .append(year)
24        .toString();
25  }
26}

15.2. With fields

1import java.lang.annotation.Retention;
2import java.lang.annotation.RetentionPolicy;
3import java.lang.reflect.Method;
 1@Retention(RetentionPolicy.RUNTIME)
 2@interface Author {
 3  String name() default "No One";
 4  String org() default "FooBar, LLC";
 5}
 6
 7@Author(name = "John Doe", org = "One-Off Coder")
 8public static class Car {
 9  private final String make, model;
10  private final int year;
11
12  public Car(String make, String model, int year) {
13    this.make = make;
14    this.model = model;
15    this.year = year;
16  }
17
18  @Author(name = "Jane Smith", org = "One-Off Coder")
19  @Override
20  public String toString() {
21    return (new StringBuilder())
22        .append(make)
23        .append(' ')
24        .append(model)
25        .append(' ')
26        .append(year)
27        .toString();
28  }
29}
 1var car = new Car("Honda", "Accord", 2019);
 2
 3Class<?> clazz = car.getClass();
 4var clazzAuthor = clazz.getAnnotation(Author.class);
 5
 6System.out.println(clazzAuthor.name() + " from " + clazzAuthor.org());
 7
 8Method method = clazz.getMethod("toString");
 9var methodAuthor = method.getAnnotation(Author.class);
10
11System.out.println(methodAuthor.name() + " from " + methodAuthor.org());

15.3. Target

1import java.lang.annotation.ElementType;
2import java.lang.annotation.Retention;
3import java.lang.annotation.RetentionPolicy;
4import java.lang.annotation.Target;
 1@Retention(RetentionPolicy.RUNTIME)
 2@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
 3@interface NeedsWork {}
 4
 5
 6public static class Car {
 7  private final String make, model;
 8  private final int year;
 9
10  @NeedsWork
11  public Car(String make, String model, int year) {
12    this.make = make;
13    this.model = model;
14    this.year = year;
15  }
16
17  @NeedsWork
18  @Override
19  public String toString() {
20    return (new StringBuilder())
21        .append(make)
22        .append(' ')
23        .append(model)
24        .append(' ')
25        .append(year)
26        .toString();
27  }
28}

15.4. Repeatable

1import java.lang.annotation.Retention;
2import java.lang.annotation.RetentionPolicy;
 1@Retention(RetentionPolicy.RUNTIME)
 2@java.lang.annotation.Repeatable(TodoRepeat.class)
 3@interface Todo {
 4  String description();
 5}
 6
 7@Retention(RetentionPolicy.RUNTIME)
 8@interface TodoRepeat {
 9  Todo[] value();
10}
11
12public static class Car {
13  private final String make, model;
14  private final int year;
15
16  public Car(String make, String model, int year) {
17    this.make = make;
18    this.model = model;
19    this.year = year;
20  }
21
22  @Todo(description = "use regular string concatenation?")
23  @Todo(description = "unit test?")
24  @Override
25  public String toString() {
26    return (new StringBuilder())
27        .append(make)
28        .append(' ')
29        .append(model)
30        .append(' ')
31        .append(year)
32        .toString();
33  }
34}