Working with Annotations
1. Using Built-in Annotations
| Annotation | Purpose |
|---|---|
@Override | Compile-time check of override |
@Deprecated(since, forRemoval) | Mark obsolete API |
@SuppressWarnings("unchecked") | Silence specific warnings |
@FunctionalInterface | Enforce SAM |
@SafeVarargs | Suppress generic varargs warning |
@Native | JNI field marker |
2. Creating Custom Annotations (@interface)
| Element | Syntax |
|---|---|
| Declaration | public @interface Audit { } |
| Element | String value() default ""; |
| Allowed types | primitive, String, Class, enum, annotation, array |
| Single-element shortcut | name value → use @Audit("info") |
Example: Custom annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit {
String value() default "";
Level level() default Level.INFO;
}
3. Using Meta-Annotations
| Meta | Effect |
|---|---|
@Target | Allowed element types |
@Retention | Visibility (SOURCE/CLASS/RUNTIME) |
@Documented | Include in Javadoc |
@Inherited | Subclass inherits class-level annotation |
@Repeatable | Allow repeated use |
4. Setting Retention Policies
| Policy | Available | Example |
|---|---|---|
| SOURCE | Compiler only | @Override |
| CLASS | In .class, not loaded | Default; build-time tools |
| RUNTIME | Reflective access | DI, ORM, validation |
5. Defining Annotation Elements
| Feature | Detail |
|---|---|
| Default | String value() default ""; |
| Array | String[] tags() default {}; |
| Enum | Level lvl() default Level.INFO; |
| Class | Class<?> type() default Object.class; |
| Nested annotation | Allowed |
| Required | No default → must specify |
6. Using Repeating Annotations (@Repeatable)
| Step | Code |
|---|---|
| Annotation | @Repeatable(Roles.class) @interface Role { String value(); } |
| Container | @interface Roles { Role[] value(); } |
| Read | method.getAnnotationsByType(Role.class) |
7. Processing Annotations at Runtime
| API | Purpose |
|---|---|
cls.isAnnotationPresent(A.class) | Check existence |
cls.getAnnotation(A.class) | Get instance |
cls.getDeclaredAnnotations() | All on this element |
cls.getAnnotationsByType(A.class) | Repeatable |
Example: Audit interceptor
for (Method m : svc.getClass().getMethods()) {
Audit a = m.getAnnotation(Audit.class);
if (a != null) log.info("audit:{} method={}", a.value(), m.getName());
}
8. Creating Type Annotations (@Target(TYPE_USE))
| Use Site | Example |
|---|---|
| Cast | (@NonNull String) obj |
| Generics | List<@NonNull String> |
| throws | void m() throws @Critical Exception |
| Receiver | void m(@ReadOnly Foo this) |
9. Understanding Annotation Inheritance
| Scenario | Inherited? |
|---|---|
Class with @Inherited annotation | Yes (class hierarchy only) |
| Interface annotations | No |
| Method overrides | No (always) |
| Field annotations | No |
10. Using @SafeVarargs for Heap Pollution
| Rule | Detail |
|---|---|
| Where | final/static/private methods, constructors, Java 9+ private instance |
| When | Body never writes to varargs array nor leaks it |
| Effect | Suppresses unchecked warning at call site |