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/