KEMBAR78
Custom Annotations in Java with Project Lombok | PDF
Yann-Gaël Guéhéneuc
(/jan/, he/il)
Work licensed under Creative Commons
BY-NC-SA 4.0 International
Custom Annotations
in Java with
Project Lombok
yann-gael.gueheneuc@concordia.ca
Version 1.0
2024/04/15
2/60
Problem: How to annotate code constituents
with metadata to guide compilation, execution?
Solution: Provide ad-hoc annotations
3/60
Ad-hoc Annotations
 Modifiers
 Javadoc tags
 Built-in annotations
Problem: How to annotate code constituents
with metadata to guide compilation, execution?
Solution: Provide ad-hoc annotations
4/60
Ad-hoc Annotations
 Modifiers
– Since JDK v1.0 (1996)
– Examples: transient, volatile
 Javadoc tags
 Built-in annotations
Problem: How to annotate code constituents
with metadata to guide compilation, execution?
Solution: Provide ad-hoc annotations
5/60
Ad-hoc Annotations
 Modifiers
 Javadoc tags
– Since JDK v1.0
– Examples: @Deprecated, @throws
 Built-in annotations
Problem: How to annotate code constituents
with metadata to guide compilation, execution?
Solution: Provide ad-hoc annotations
6/60
Ad-hoc Annotations
 Modifiers
 Javadoc tags
 Built-in annotations
– Since JDK v1.5 (2004)
– Example: @Override, @interface
Problem: How to annotate code constituents
with metadata to guide compilation, execution?
Solution: Provide ad-hoc annotations
7/60
Kinds of Annotations
https://www.geeksforgeeks.org/annotations-in-java/
8/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
9/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
Declared by JUnit
10/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
@MetaInfServices(JavacAnnotationHandler.class)
public class SingletonHandler extends JavacAnnotationHandler<...> {
public void handle(
final AnnotationValues<...> annotation,
final JCTree.JCAnnotation ast,
final JavacNode annotationNode) {
...
11/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
@MetaInfServices(JavacAnnotationHandler.class)
public class SingletonHandler extends JavacAnnotationHandler<...> {
public void handle(
final AnnotationValues<...> annotation,
final JCTree.JCAnnotation ast,
final JavacNode annotationNode) {
...
One value
12/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Singleton {
}
13/60
Kinds of Annotations
 Marker annotations
 Value annotations
 Meta annotations
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Singleton {
}
Meta-data on
an annotation
14/60
Problem: How to annotate code constituents with
metadata to guide compilation, execution?
Solution: Provide general annotation mechanisms
15/60
Annotation Mechanisms
 Reflection (i.e., introspection)
 Truly general mechanism
Problem: How to annotate code constituents with
metadata to guide compilation, execution?
Solution: Provide general annotation mechanisms
16/60
Annotation Mechanisms
 Reflection (i.e., introspection)
– Since JDK v1.5 (2004)
– Example: java.lang.reflect.Method.
getAnnotation(Class<T> annotationClass)
 Truly general mechanism
Problem: How to annotate code constituents with
metadata to guide compilation, execution?
Solution: Provide general annotation mechanisms
17/60
Annotation Mechanisms
 Reflection (i.e., introspection)
 Truly general mechanism
– Since JDK v1.6 (2006)
– javax.annotation.processing.Processor
Problem: How to annotate code constituents with
metadata to guide compilation, execution?
Solution: Provide general annotation mechanisms
18/60
Annotation Mechanisms
 Both introspection and Processor can
only read annotations (and their value)
and, possibly, generate new files
https://www.baeldung.com/java-annotation-processing-builder
19/60
Annotation Mechanisms
 Reflection (i.e., introspection)
– JUnit v4+
– Since 2006
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
20/60
Annotation Mechanisms
 Reflection (i.e., introspection)
– JUnit v4+
– Since 2006
public class TestClass implements Annotatable {
protected void scanAnnotatedMembers(
Map<Class<...>, List<...>> methodsForAnnotations,
Map<Class<...>, List<...>> fieldsForAnnotations) {
for (Class<?> eachClass : getSuperClasses(clazz)) {
for (Method eachMethod : ...(eachClass)) {
// Simplified!
for (Annotation each : eachMethod.getAnnotations()) {
// ...
21/60
Annotation Mechanisms
 Reflection (i.e., introspection)
– JUnit v4+
– Since 2006
public class TestClass implements Annotatable {
protected void scanAnnotatedMembers(
Map<Class<...>, List<...>> methodsForAnnotations,
Map<Class<...>, List<...>> fieldsForAnnotations) {
for (Class<?> eachClass : getSuperClasses(clazz)) {
for (Method eachMethod : ...(eachClass)) {
// Simplified!
for (Annotation each : eachMethod.getAnnotations()) {
// ...
Provided by the JDK
22/60
Annotation Mechanisms
 Truly general mechanism
– The result is not a function of the presence or
absence of other inputs (orthogonality)
– Processing the same input produces the same
output (consistency)
– Processing input A followed by B is equivalent to
processing B then A (commutativity)
– Processing an input does not rely on the output
of other processors (independence)
https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html
23/60
Annotation Mechanisms
 Truly general mechanism
– The result is not a function of the presence or
absence of other inputs (orthogonality)
– Processing the same input produces the same
output (consistency)
– Processing input A followed by B is equivalent to
processing B then A (commutativity)
– Processing an input does not rely on the output
of other processors (independence)
https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html
24/60
Annotation Mechanisms
 Truly general mechanism
https://www.baeldung.com/java-annotation-processing-builder
@SupportedAnnotationTypes("....BuilderProperty")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(
final Set<? extends TypeElement> annotations,
final RoundEnvironment roundEnv) {
return false;
}
}
25/60
Annotation Mechanisms
 Truly general mechanism
https://www.baeldung.com/java-annotation-processing-builder
@SupportedAnnotationTypes("....BuilderProperty")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class BuilderProcessor extends AbstractProcessor {
@Override
public boolean process(
final Set<? extends TypeElement> annotations,
final RoundEnvironment roundEnv) {
return false;
}
}
Provided by the JDK,
implements Processor
26/60
Annotation Mechanisms
 Truly general mechanism
https://www.baeldung.com/java-annotation-processing-builder
private void writeBuilderFile(String className,
Map<String, String> setterMap) throws IOException {
String packageName = null;
int lastDot = className.lastIndexOf('.’);
if (lastDot > 0) { ... }
String simpleClassName = className.substring(lastDot + 1);
String builderClassName = className + "Builder";
String builderSimpleClassName = builderClassName....;
JavaFileObject builderFile = processingEnv.getFiler()
.createSourceFile(builderClassName);
try (PrintWriter out = new PrintWriter(builderFile....())) {
// ...
27/60
Problem: How does the compiler know what
annotation processors exist?
Solution: Provide general discovery mechanisms
28/60
 Annotation processor tool
 Compiler argument
 Processor JAR
 Auto-service Library
 Maven
Problem: How does the compiler know what
annotation processors exist?
Solution: Provide general discovery mechanisms
Discovery Mechanisms
29/60
 Annotation processor tool
 Compiler argument
 Processor JAR
 Auto-service Library
 Maven
Problem: How does the compiler know what
annotation processors exist?
Solution: Provide general discovery mechanisms
Discovery Mechanisms
30/60
Discovery Mechanisms
 Compiler argument
javac -processor package1.Processor1,package2.Processor2 SourceFile.java
https://www.baeldung.com/java-annotation-processing-builder
31/60
Discovery Mechanisms
 Compiler argument
javac -processor package1.Processor1,package2.Processor2 SourceFile.java
javac -processor com.baeldung.annotation.processor.MyProcessor Person.java
https://www.baeldung.com/java-annotation-processing-builder
32/60
Discovery Mechanisms
 Processor JAR
 Auto-service Library
META-INF/services/javax.annotation.processing.Processor
@AutoService(Processor.class)
public BuilderProcessor extends AbstractProcessor {
// ...
}
33/60
Discovery Mechanisms
 Processor JAR
 Auto-service Library
META-INF/services/javax.annotation.processing.Processor
@AutoService(Processor.class)
public BuilderProcessor extends AbstractProcessor {
// ...
}
34/60
Discovery Mechanisms
 Processor JAR
 Auto-service Library
META-INF/services/javax.annotation.processing.Processor
@AutoService(Processor.class)
public BuilderProcessor extends AbstractProcessor {
// ...
}
The “magic” happens (in) here
35/60
Problem: How to modify code constituents using
annotation during compilation?
Solution: Hook into the compiler and hack its AST
36/60
https://www.southernexposure.com/products/lombok-chile-lombak-hot-pepper/
37/60
Caveats
 Only Lombok v1.14.8
 Only JDK v1.8 of 2014
– Until JDK v1.9 in 2017
• Why the gap?
• Because of modularisation!
38/60
Caveats
 Only Lombok v1.14.8
 Only JDK v1.8 of 2014
– Until JDK v1.9 in 2017
• Why the gap?
• Because of modularisation!
39/60
Caveats
 Only Lombok v1.14.8
 Only JDK v1.8 of 2014
– Until JDK v1.9 in 2017
• Why the gap?
• Because of modularisation!
Don’t try with Lombok 1.18+
Don’t even try with JDK 22!
40/60
Singleton Design Pattern
 Of course
public class AnotherSingleton {
private static class AnotherSingletonHolder {
private static AnotherSingleton UNIQUE_INSTANCE
= new AnotherSingleton();
}
public static AnotherSingleton getInstance() {
return AnotherSingletonHolder.UNIQUE_INSTANCE;
}
private AnotherSingleton() {
}
// Some other methods
}
https://www.baeldung.com/lombok-custom-annotation
41/60
Singleton Design Pattern
 Of course
public class AnotherSingleton {
private static class AnotherSingletonHolder {
private static AnotherSingleton UNIQUE_INSTANCE
= new AnotherSingleton();
}
public static AnotherSingleton getInstance() {
return AnotherSingletonHolder.UNIQUE_INSTANCE;
}
private AnotherSingleton() {
}
// Some other methods
}
What happens
with this class?
https://www.baeldung.com/lombok-custom-annotation
42/60
Singleton Design Pattern
 Much simpler
@Singleton
public class MySingleton {
// Some other methods
}
43/60
Several Steps
1. Create @Singleton annotation
2. Create JavacAnnotationHandler
– Or EclipseAnnotationHandler
3. Compile handler
4. Register handler
5. Compile classes that use singletons
6. Run the tests or the program!
https://projectlombok.org/contributing/lombok-execution-path
44/60
Several Steps
1. Create @Singleton annotation
2. Create JavacAnnotationHandler
– Or EclipseAnnotationHandler
3. Compile handler
4. Register handler
5. Compile classes that use singletons
6. Run the tests or the program!
Provided by the
Lombok library
https://projectlombok.org/contributing/lombok-execution-path
45/60
Step 1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Singleton {
}
@Singleton
public class MySingleton {
}
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
46/60
Step 1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Singleton {
}
@Singleton
public class MySingleton {
}
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
What happens
with this call?
47/60
Step 1
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Singleton {
}
@Singleton
public class MySingleton {
}
public class TestSingleton {
@Test
public void test() {
final MySingleton msc = MySingleton.getInstance();
System.out.println(msc);
Assert.assertNotNull(msc);
}
}
The method getInstance()
is undefined for the type
MySingleton
48/60
Step 2
49/60
Step 3
 Without full paths, simplified
javac.exe
-d target/classes
-classpath target/classes;.m2/repository/com/sun/tools/tools/1.8/
tools-1.8.jar;.m2/repository/org/projectlombok/lombok/1.14.8/
lombok-1.14.8.jar;.m2/repository/org/kohsuke/metainf-services/
metainf-services/1.8/metainf-services-1.8.jar
src/main/java/.../singleton/example/MySingleton.java
src/main/java/.../singleton/Singleton.java
src/main/java/.../singleton/javac/SingletonHandler.java
50/60
Step 3
51/60
Step 4
 Done automatically by Lombok
Note: Writing META-INF/services/lombok.javac.JavacAnnotationHandler
52/60
Step 5
 Without full paths, simplified
javac.exe
-d target/classes
-classpath target/classes;.m2/repository/org/projectlombok/lombok/
1.14.8/lombok-1.14.8.jar;.m2/repository/junit/junit/4.13.2/junit-
4.13.2.jar
src/main/java/.../singleton/example/MySingleton.java
src/test/java/.../singleton/test/TestSingleton.java
53/60
Step 5
54/60
Step 6
 Without full paths, simplified
java.exe –classpath target/classes;.m2/repository/org/hamcrest/
hamcrest-core/1.3/hamcrest-core-1.3.jar;.m2/repository/junit/junit/
4.13.2/junit-4.13.2.jar
org.junit.runner.JUnitCore
net.ptidej.tutorial.lombok.singleton.test.TestSingleton
55/60
Step 6
 Without full paths, simplified
java.exe –classpath target/classes;.m2/repository/org/hamcrest/
hamcrest-core/1.3/hamcrest-core-1.3.jar;.m2/repository/junit/junit/
4.13.2/junit-4.13.2.jar
org.junit.runner.JUnitCore
net.ptidej.tutorial.lombok.singleton.test.TestSingleton
JUnit version 4.13.2
.net.ptidej.tutorial.lombok.singleton.example.MySingleton@4d76f3f8
Time: 0.029
OK (1 test)
56/60
Conclusion
 Annotations
– Meta-data
 Code generation
 Code transformation
 Other considerations
– Aspect Oriented
Programming
– Spring Boot
Future work?
57/60
Conclusion
 Annotations
– Meta-data
 Code generation
 Code transformation
 Other considerations
– Aspect Oriented
Programming
– Spring Boot
Future work?
58/60
Conclusion
 Annotations
– Meta-data
 Code generation
 Code transformation
 Other considerations
– Aspect Oriented
Programming
– Spring Boot
Future work?
59/60
60/60
Image Credits
 https://levelup.gitconnected.com/lombok-to-use-or-
not-to-use-that-is-the-blog-e7a3a8f97e8f
 https://forums.sherdog.com/threads/best-
simpsons-episode-ever.3855795/
 https://tenor.com/en-GB/search/homer-simpson-
with-hair-gifs
 https://www.facebook.com/eagertolearnJava/

Custom Annotations in Java with Project Lombok

  • 1.
    Yann-Gaël Guéhéneuc (/jan/, he/il) Worklicensed under Creative Commons BY-NC-SA 4.0 International Custom Annotations in Java with Project Lombok yann-gael.gueheneuc@concordia.ca Version 1.0 2024/04/15
  • 2.
    2/60 Problem: How toannotate code constituents with metadata to guide compilation, execution? Solution: Provide ad-hoc annotations
  • 3.
    3/60 Ad-hoc Annotations  Modifiers Javadoc tags  Built-in annotations Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide ad-hoc annotations
  • 4.
    4/60 Ad-hoc Annotations  Modifiers –Since JDK v1.0 (1996) – Examples: transient, volatile  Javadoc tags  Built-in annotations Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide ad-hoc annotations
  • 5.
    5/60 Ad-hoc Annotations  Modifiers Javadoc tags – Since JDK v1.0 – Examples: @Deprecated, @throws  Built-in annotations Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide ad-hoc annotations
  • 6.
    6/60 Ad-hoc Annotations  Modifiers Javadoc tags  Built-in annotations – Since JDK v1.5 (2004) – Example: @Override, @interface Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide ad-hoc annotations
  • 7.
  • 8.
    8/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } }
  • 9.
    9/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } } Declared by JUnit
  • 10.
    10/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations @MetaInfServices(JavacAnnotationHandler.class) public class SingletonHandler extends JavacAnnotationHandler<...> { public void handle( final AnnotationValues<...> annotation, final JCTree.JCAnnotation ast, final JavacNode annotationNode) { ...
  • 11.
    11/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations @MetaInfServices(JavacAnnotationHandler.class) public class SingletonHandler extends JavacAnnotationHandler<...> { public void handle( final AnnotationValues<...> annotation, final JCTree.JCAnnotation ast, final JavacNode annotationNode) { ... One value
  • 12.
    12/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Singleton { }
  • 13.
    13/60 Kinds of Annotations Marker annotations  Value annotations  Meta annotations @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Singleton { } Meta-data on an annotation
  • 14.
    14/60 Problem: How toannotate code constituents with metadata to guide compilation, execution? Solution: Provide general annotation mechanisms
  • 15.
    15/60 Annotation Mechanisms  Reflection(i.e., introspection)  Truly general mechanism Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide general annotation mechanisms
  • 16.
    16/60 Annotation Mechanisms  Reflection(i.e., introspection) – Since JDK v1.5 (2004) – Example: java.lang.reflect.Method. getAnnotation(Class<T> annotationClass)  Truly general mechanism Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide general annotation mechanisms
  • 17.
    17/60 Annotation Mechanisms  Reflection(i.e., introspection)  Truly general mechanism – Since JDK v1.6 (2006) – javax.annotation.processing.Processor Problem: How to annotate code constituents with metadata to guide compilation, execution? Solution: Provide general annotation mechanisms
  • 18.
    18/60 Annotation Mechanisms  Bothintrospection and Processor can only read annotations (and their value) and, possibly, generate new files https://www.baeldung.com/java-annotation-processing-builder
  • 19.
    19/60 Annotation Mechanisms  Reflection(i.e., introspection) – JUnit v4+ – Since 2006 public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } }
  • 20.
    20/60 Annotation Mechanisms  Reflection(i.e., introspection) – JUnit v4+ – Since 2006 public class TestClass implements Annotatable { protected void scanAnnotatedMembers( Map<Class<...>, List<...>> methodsForAnnotations, Map<Class<...>, List<...>> fieldsForAnnotations) { for (Class<?> eachClass : getSuperClasses(clazz)) { for (Method eachMethod : ...(eachClass)) { // Simplified! for (Annotation each : eachMethod.getAnnotations()) { // ...
  • 21.
    21/60 Annotation Mechanisms  Reflection(i.e., introspection) – JUnit v4+ – Since 2006 public class TestClass implements Annotatable { protected void scanAnnotatedMembers( Map<Class<...>, List<...>> methodsForAnnotations, Map<Class<...>, List<...>> fieldsForAnnotations) { for (Class<?> eachClass : getSuperClasses(clazz)) { for (Method eachMethod : ...(eachClass)) { // Simplified! for (Annotation each : eachMethod.getAnnotations()) { // ... Provided by the JDK
  • 22.
    22/60 Annotation Mechanisms  Trulygeneral mechanism – The result is not a function of the presence or absence of other inputs (orthogonality) – Processing the same input produces the same output (consistency) – Processing input A followed by B is equivalent to processing B then A (commutativity) – Processing an input does not rely on the output of other processors (independence) https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html
  • 23.
    23/60 Annotation Mechanisms  Trulygeneral mechanism – The result is not a function of the presence or absence of other inputs (orthogonality) – Processing the same input produces the same output (consistency) – Processing input A followed by B is equivalent to processing B then A (commutativity) – Processing an input does not rely on the output of other processors (independence) https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html
  • 24.
    24/60 Annotation Mechanisms  Trulygeneral mechanism https://www.baeldung.com/java-annotation-processing-builder @SupportedAnnotationTypes("....BuilderProperty") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class BuilderProcessor extends AbstractProcessor { @Override public boolean process( final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { return false; } }
  • 25.
    25/60 Annotation Mechanisms  Trulygeneral mechanism https://www.baeldung.com/java-annotation-processing-builder @SupportedAnnotationTypes("....BuilderProperty") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class BuilderProcessor extends AbstractProcessor { @Override public boolean process( final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { return false; } } Provided by the JDK, implements Processor
  • 26.
    26/60 Annotation Mechanisms  Trulygeneral mechanism https://www.baeldung.com/java-annotation-processing-builder private void writeBuilderFile(String className, Map<String, String> setterMap) throws IOException { String packageName = null; int lastDot = className.lastIndexOf('.’); if (lastDot > 0) { ... } String simpleClassName = className.substring(lastDot + 1); String builderClassName = className + "Builder"; String builderSimpleClassName = builderClassName....; JavaFileObject builderFile = processingEnv.getFiler() .createSourceFile(builderClassName); try (PrintWriter out = new PrintWriter(builderFile....())) { // ...
  • 27.
    27/60 Problem: How doesthe compiler know what annotation processors exist? Solution: Provide general discovery mechanisms
  • 28.
    28/60  Annotation processortool  Compiler argument  Processor JAR  Auto-service Library  Maven Problem: How does the compiler know what annotation processors exist? Solution: Provide general discovery mechanisms Discovery Mechanisms
  • 29.
    29/60  Annotation processortool  Compiler argument  Processor JAR  Auto-service Library  Maven Problem: How does the compiler know what annotation processors exist? Solution: Provide general discovery mechanisms Discovery Mechanisms
  • 30.
    30/60 Discovery Mechanisms  Compilerargument javac -processor package1.Processor1,package2.Processor2 SourceFile.java https://www.baeldung.com/java-annotation-processing-builder
  • 31.
    31/60 Discovery Mechanisms  Compilerargument javac -processor package1.Processor1,package2.Processor2 SourceFile.java javac -processor com.baeldung.annotation.processor.MyProcessor Person.java https://www.baeldung.com/java-annotation-processing-builder
  • 32.
    32/60 Discovery Mechanisms  ProcessorJAR  Auto-service Library META-INF/services/javax.annotation.processing.Processor @AutoService(Processor.class) public BuilderProcessor extends AbstractProcessor { // ... }
  • 33.
    33/60 Discovery Mechanisms  ProcessorJAR  Auto-service Library META-INF/services/javax.annotation.processing.Processor @AutoService(Processor.class) public BuilderProcessor extends AbstractProcessor { // ... }
  • 34.
    34/60 Discovery Mechanisms  ProcessorJAR  Auto-service Library META-INF/services/javax.annotation.processing.Processor @AutoService(Processor.class) public BuilderProcessor extends AbstractProcessor { // ... } The “magic” happens (in) here
  • 35.
    35/60 Problem: How tomodify code constituents using annotation during compilation? Solution: Hook into the compiler and hack its AST
  • 36.
  • 37.
    37/60 Caveats  Only Lombokv1.14.8  Only JDK v1.8 of 2014 – Until JDK v1.9 in 2017 • Why the gap? • Because of modularisation!
  • 38.
    38/60 Caveats  Only Lombokv1.14.8  Only JDK v1.8 of 2014 – Until JDK v1.9 in 2017 • Why the gap? • Because of modularisation!
  • 39.
    39/60 Caveats  Only Lombokv1.14.8  Only JDK v1.8 of 2014 – Until JDK v1.9 in 2017 • Why the gap? • Because of modularisation! Don’t try with Lombok 1.18+ Don’t even try with JDK 22!
  • 40.
    40/60 Singleton Design Pattern Of course public class AnotherSingleton { private static class AnotherSingletonHolder { private static AnotherSingleton UNIQUE_INSTANCE = new AnotherSingleton(); } public static AnotherSingleton getInstance() { return AnotherSingletonHolder.UNIQUE_INSTANCE; } private AnotherSingleton() { } // Some other methods } https://www.baeldung.com/lombok-custom-annotation
  • 41.
    41/60 Singleton Design Pattern Of course public class AnotherSingleton { private static class AnotherSingletonHolder { private static AnotherSingleton UNIQUE_INSTANCE = new AnotherSingleton(); } public static AnotherSingleton getInstance() { return AnotherSingletonHolder.UNIQUE_INSTANCE; } private AnotherSingleton() { } // Some other methods } What happens with this class? https://www.baeldung.com/lombok-custom-annotation
  • 42.
    42/60 Singleton Design Pattern Much simpler @Singleton public class MySingleton { // Some other methods }
  • 43.
    43/60 Several Steps 1. Create@Singleton annotation 2. Create JavacAnnotationHandler – Or EclipseAnnotationHandler 3. Compile handler 4. Register handler 5. Compile classes that use singletons 6. Run the tests or the program! https://projectlombok.org/contributing/lombok-execution-path
  • 44.
    44/60 Several Steps 1. Create@Singleton annotation 2. Create JavacAnnotationHandler – Or EclipseAnnotationHandler 3. Compile handler 4. Register handler 5. Compile classes that use singletons 6. Run the tests or the program! Provided by the Lombok library https://projectlombok.org/contributing/lombok-execution-path
  • 45.
    45/60 Step 1 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interfaceSingleton { } @Singleton public class MySingleton { } public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } }
  • 46.
    46/60 Step 1 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interfaceSingleton { } @Singleton public class MySingleton { } public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } } What happens with this call?
  • 47.
    47/60 Step 1 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interfaceSingleton { } @Singleton public class MySingleton { } public class TestSingleton { @Test public void test() { final MySingleton msc = MySingleton.getInstance(); System.out.println(msc); Assert.assertNotNull(msc); } } The method getInstance() is undefined for the type MySingleton
  • 48.
  • 49.
    49/60 Step 3  Withoutfull paths, simplified javac.exe -d target/classes -classpath target/classes;.m2/repository/com/sun/tools/tools/1.8/ tools-1.8.jar;.m2/repository/org/projectlombok/lombok/1.14.8/ lombok-1.14.8.jar;.m2/repository/org/kohsuke/metainf-services/ metainf-services/1.8/metainf-services-1.8.jar src/main/java/.../singleton/example/MySingleton.java src/main/java/.../singleton/Singleton.java src/main/java/.../singleton/javac/SingletonHandler.java
  • 50.
  • 51.
    51/60 Step 4  Doneautomatically by Lombok Note: Writing META-INF/services/lombok.javac.JavacAnnotationHandler
  • 52.
    52/60 Step 5  Withoutfull paths, simplified javac.exe -d target/classes -classpath target/classes;.m2/repository/org/projectlombok/lombok/ 1.14.8/lombok-1.14.8.jar;.m2/repository/junit/junit/4.13.2/junit- 4.13.2.jar src/main/java/.../singleton/example/MySingleton.java src/test/java/.../singleton/test/TestSingleton.java
  • 53.
  • 54.
    54/60 Step 6  Withoutfull paths, simplified java.exe –classpath target/classes;.m2/repository/org/hamcrest/ hamcrest-core/1.3/hamcrest-core-1.3.jar;.m2/repository/junit/junit/ 4.13.2/junit-4.13.2.jar org.junit.runner.JUnitCore net.ptidej.tutorial.lombok.singleton.test.TestSingleton
  • 55.
    55/60 Step 6  Withoutfull paths, simplified java.exe –classpath target/classes;.m2/repository/org/hamcrest/ hamcrest-core/1.3/hamcrest-core-1.3.jar;.m2/repository/junit/junit/ 4.13.2/junit-4.13.2.jar org.junit.runner.JUnitCore net.ptidej.tutorial.lombok.singleton.test.TestSingleton JUnit version 4.13.2 .net.ptidej.tutorial.lombok.singleton.example.MySingleton@4d76f3f8 Time: 0.029 OK (1 test)
  • 56.
    56/60 Conclusion  Annotations – Meta-data Code generation  Code transformation  Other considerations – Aspect Oriented Programming – Spring Boot Future work?
  • 57.
    57/60 Conclusion  Annotations – Meta-data Code generation  Code transformation  Other considerations – Aspect Oriented Programming – Spring Boot Future work?
  • 58.
    58/60 Conclusion  Annotations – Meta-data Code generation  Code transformation  Other considerations – Aspect Oriented Programming – Spring Boot Future work?
  • 59.
  • 60.
    60/60 Image Credits  https://levelup.gitconnected.com/lombok-to-use-or- not-to-use-that-is-the-blog-e7a3a8f97e8f https://forums.sherdog.com/threads/best- simpsons-episode-ever.3855795/  https://tenor.com/en-GB/search/homer-simpson- with-hair-gifs  https://www.facebook.com/eagertolearnJava/