What Are Annotations? π§
They allow us to mark (annotate) certain Java language elements as having certain properties (annotations).
What Elements?
- Package, Class, Method, Field, Parameter.
What Are They Used For? π€
There has been a growing trend in the Java world towards annotating elements as having particular attributes that indicate they should be processed in special ways by development tools, deployment tools, or run-time libraries.
Mainly, they are used either on:
Compile time π
- To examine classes and issue compilation errors or warnings.
- To create new source files.
Run time π
- take actions to do accomplish some task based on the annotations, for example to validate parameters given to a method.
Let's look at two examples using Java annotations π
- Embed instructions for the Java compiler or source code processing tools (please generate getters for my fields using Lombok annotations).
@Getter @Setter
public class Shipment {
private Integer id;
private String serialNumber;
}
- Embed instructions that can be read on run time (using reflection) by your app or third party libraries (Spring for example).
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Creating Your Own Annotations π€
Let's create an annotation called CoolAnnotation
which we want to be accessible in compilation time and usable only by types (Classes, Interfaces or Enums).
We also want to add a name
value which must be specified by the user.
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface CoolAnnotation {
String name();
}
Let's use it on a class
@CoolAnnotation(name="myName")
public class ShipmentService {
// buisness things
}
How To Use This Annotation? π§
On Runtime π
We can read those annotations at runtime and choose to take actions based on their values
Let's introduce the same cool annotation we had before, but this time let's make it visible on runtime
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CoolAnnotation {
String name();
}
And annotate it to the service class
@CoolAnnotation(name="myName")
public class ShipmentService {
}
Now let's test it on runtime
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ShipmentAnnotationTest {
@Test
public void testAnnotation()
{
String name = ShipmentService
.class
.getAnnotation(CoolAnnotation.class)
.name();
assertEquals("myName", name); // lights green
}
}
On Compile time π
This is done via compile time annotation processors.
Processors can
Create new resource files.
Create new code source files.
Issue note, warnings and errors which can cause the compilation to fail (picked up by the IDE).
They can't modify existing resources or source code files.
Writing a processor βοΈ
It's a topic that requires a post on its own, however you can watch this excellent YouTube video on the topic.
Conclusion π©βπ π§βπ
Annotations allow us to give Java elements some properties (meta-data) that are used either at compile time or runtime.
This offers major benefits to the Java world like offering static type checking at compile time, automated processing at runtime. This is used heavily in frameworks like Spring and Hibernate.
Top comments (0)