Annotations
Java Annotations vs Python Decorators
- They both share the same syntax
- A decorator takes a function and return another function
- Java annotations are just metadata and read by annotation processors
- Java annotations are not decorators and hence not equivalent to python decorators
@Override
- To override the function while extending/implementing another class
- This is an optional annotation but it is recommended to use it for two benefits:
- Compiler will check if the method is really overriding and throw error if it is not
- The developer instantly knows that the method is overriding
@Deprecated
- marked element is deprecated and should no longer be used
- should also be documented using the Javadoc
@deprecated tag
/**
* @deprecated
* explanation of why it was deprecated
*/
@Deprecated
static void deprecatedMethod() { }
@SuppressWarnings
- tells the compiler to suppress specific warnings that it would otherwise generate
- Two most common warnings are deprecation and unchecked.:
deprecation: when using deprecated method or type
unchecked: when using raw types
@SuppressWarnings("deprecation")
- https://www.baeldung.com/java-suppresswarnings
@FunctionalInterface
- Indicate that the interface must have a single abstract method (SAM) inside
- It must be used with interface
- If any condition not fulfilled then compilation will fail as per Java Language spec
- See functional_interface
@SafeVarargs
- applied to a method or constructor
- asserts that the code does not perform potentially unsafe operations on its
varargs parameter.
// No warning thrown
private void printStringSafeVarargs(String... testStrings) {
}
// Throws warning since varargs used on generics
@SafeVarargs // suppress warnings
private void printStringSafeVarargs(List<String>... testStringLists) {
}
Custom Annotations
- Need to be defined in
@interface files
- Meta-Annotation:
- Annotations that apply to annotations are called meta-annotation
@Retention: Retention Policies, how long annotation will be retained
RetentionPolicy.SOURCE
- used by the compiler during the compilation process
- example:
@Override
RetentionPolicy.CLASS
- default retention
- recorded in class file generation
- not available in runtime
- used on code obfuscation or code generation (Lombok)
- example:
@NotNull
RetentionPolicy.RUNTIME
- recorded in the class file
- available to read at runtime
- used for custom annotation
- example:
@Deprecated
@Target: Target types
ElementType.ANNOTATION_TYPE can be applied to an annotation type.
ElementType.CONSTRUCTOR — constructor.
ElementType.FIELD — field or property.
ElementType.LOCAL_VARIABLE — local variable.
ElementType.METHOD — method-level annotation.
ElementType.PACKAGE — package declaration.
ElementType.PARAMETER — parameters of a method.
ElementType.TYPE— any element of a class.
@Documented - takes no parameters and includes an annotation in the Javadoc, considered part of the element’s public contract
@Inherited - will be applied to all subclasses of the annotated class
@Repeatable - can be used multiple times at the same place
@Retention(RetentionPolicy.RUNTIME) // since it is custom annotation
@Target(ElementType.METHOD) // works on methods
public @interface Description {
}
@Repeatable
- Provide a container annotation as argument
- Define container annotation with
value() element with an array type
- For compatibility reasons, repeating annotations are stored in a container annotation that is automatically generated by the Java compiler
- In order for the compiler to do this, two declarations are required in your code:
- @Repeatable annotation
- Container annotation type
- https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
// Container annotation
public @interface Schedules {
Schedule[] value();
}
// using the annotation
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
Annotation Parameters
- They can only be of the following types:
- Primitives
- String
- Class
- Enum
- annotation
- an array of these types
- default value cannot be
null
- If you don’t want to use the argument name, then name method as
value()
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Description {
String author();
String description();
int version() default 0;
}
Annotation Preprocessor
- https://www.baeldung.com/java-annotation-processing-builder
- Used by JPA, QueryDSL, Lombok etc.
- You can only generate new files but cannot modify the existing ones
- Lombok is an exception which uses some hacks to achieve its functionality
- We create separate java module for Processor
- The main logic class extends
AbstractProcessor
- The processor can be invoked using
- CLI
javac -processor <processor-class> <main-class>
- maven
- gradle