Code Generation in the Java Compiler Annotation Processors Do the Hard Work JavaOne Conference – CON2013 – October 2014 Copyright © 2014 Accenture. All rights reserved.
Code Generation in the Java Compiler Objectives for the session: • Introduce Annotations and Annotation Processors • Learn how to create Annotation Processors • Learn how to use Annotation Processors to generate source code • Connect Annotation Processors with external generation engines • Integration with IDEs and build automation tools • With lots of examples and source code Copyright © 2014 Accenture. All rights reserved. 1
About the Speaker Jorge Hidalgo @_deors Accenture, Malaga (Spain) Senior Technology Architect Java Lead at the Accenture Delivery Center in Spain 15 years of IT professional experience across industries From time to time writing a blog called Dr. MacPhail’s Trance: http://deors.wordpress.com Father of two children, husband, whistle player, video gamer, sci-fi junkie, Raspberry Pi fan... Copyright © 2014 Accenture. All rights reserved. 2
Code Generation – Why? • To not repeat the same tasks again and again • To reduce the burden of boilerplate code • To standardize code patterns, follow common idioms • To ensure that best practices are applied • To improve the adherence to coding standards (naming, style) • ... PRODUCTIVITY QUALITY PREDICTABILITY Copyright © 2014 Accenture. All rights reserved. 3
Poll #1 • Please raise your hands if you are familiar with Annotations, know how to use them or are even capable of writing Annotation Types Copyright © 2014 Accenture. All rights reserved. 4
Poll #2 • Please raise your hands if you are familiar with Annotation Processors, their capabilities or know how to write new ones Copyright © 2014 Accenture. All rights reserved. 5
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 6
Annotations in the Java Language • Annotations were first introduced in Java 5 • Add metadata capabilities to the Java language: • Build/deployment information • Configuration properties • Compiler behavior • Quality checks • Dependency injection • Persistence mapping • ... Copyright © 2014 Accenture. All rights reserved. 7
Annotations in the Java Language • Annotations always appear before the annotated piece of code • Annotations can ‘decorate’... • Packages • Types (classes, interfaces, enums, annotation types) • Variables (class, instance and local variables) • Constructors, methods and their parameters • Generic type parameter (since Java 8) • Any type use (since Java 8) • Can be grouped, nested, repeated... very powerful! Map<@NonNull String, @NonEmpty List<@Readonly Document>> docStore; Copyright © 2014 Accenture. All rights reserved. 8
Annotations in the Java Language • Annotations may be used just as a ‘marker’ @NonNull String email; • They may contain name-value pairs, and arrays @Author(name = "Albert", created = "17/09/2010", revision = 3, reviewers = {"George", "Fred"}) public class SomeClass {...} • Can be defined with default values, and then omitted when used • When it has only one attribute named value, it can be omitted, too @DatabaseTable(“MY_TABLE”) public class MyTable {...} Copyright © 2014 Accenture. All rights reserved. 9
Create an Annotation Type • A special type of interface public @interface Author { String name(); String created(); int revision() default 1; String[] reviewers() default {}; } • Only primitives, enum types, annotation types, String, Class and arrays of them are allowed as elements • May be annotated itself, i.e. to define the retention policy or targets @Retention(RetentionPolicy.SOURCE) @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE}) public @interface Author {...} Copyright © 2014 Accenture. All rights reserved. 10
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 11
Annotation Processors This is cool but I can add metadata information with Javadocs, so what’s the buzz? /** * My Class description. * @author jorge.hidalgo * @version 1.0 * @deprecated Use MyNewClass instead */ Copyright © 2014 Accenture. All rights reserved. 12
Annotation Processors • Annotations are first-class citizens in the Java language • Formalized in the Java Language Specification • Readable at run time: Class.getAnnotations() Class.getAnnotationsByType(Class<A>) Class.getDeclaredAnnotations() Class.getDeclaredAnnotationsByType(Class<A>) • Can trigger custom actions at compile time managed by Annotation Processors! Copyright © 2014 Accenture. All rights reserved. 13
Annotation Processors • When first introduced in Java 5, the Annotation Processing API was not standard • A standalone tool, apt, was needed to process annotations • Mirror API distributed in com.sun.mirror packages • Starting with Java 6, standardized through JSR-269(1) • apt, although still available for standalone execution, was seamlessly integrated into the Java compiler, javac • Annotation Processing API distributed in javax.lang.model packages • Since Java 8, apt is no longer available in the JDK (1) JSR-269, Pluggable Annotation Processing API, can be browsed online here. Copyright © 2014 Accenture. All rights reserved. 14
Annotation Processing API • Annotation Processor: • Implements javax.annotation.processing.Processor • Or extends javax.annotation.processing.AbstractProcessor • May use three annotations to configure itself: • jx.a.p.SupportedAnnotationTypes – Used to flag which Annotation Types are managed by the processor • jx.a.p.SupportedSourceVersion – Used to flag the latest Java source level supported by the processor • jx.a.p.SupportedOptions – Used to register custom parameters that may be passed through the command line • TL;DR – Implement the process() method Copyright © 2014 Accenture. All rights reserved. 15
Hello Multiverse Processor @Documented @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Complexity { ComplexityLevel value() default ComplexityLevel.MEDIUM; } public enum ComplexityLevel { VERY_SIMPLE, SIMPLE, MEDIUM, COMPLEX, VERY_COMPLEX; } @SupportedAnnotationTypes("deors.demos.annotations.base.Complexity") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ComplexityProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return true; } } Tell the compiler this processor actually handled the annotation Copyright © 2014 Accenture. All rights reserved. 16
Rounds and environment • Annotation processing happens in ‘rounds’ • In each round, a subset of sources are compiled, and then processors matching the annotations found on those sources are called • Processing ends when no more sources/annotations are pending • Processors may claim all annotation types with a wildcard • process() method has two parameters: • Set<? extends jx.lang.model.element.TypeElement> – subset of annotations being processed • jx.a.p.RoundEnvironment – access to information about the current and previous round Copyright © 2014 Accenture. All rights reserved. 17
Rounds and environment • When extending jx.a.p.AbstractProcessor, there is available an instance variable of type jx.a.p.ProcessingEnvironment with access to a specialized logging tool, the Messager @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element elem : roundEnv.getElementsAnnotatedWith(Complexity.class)) { Complexity complexity = elem.getAnnotation(Complexity.class); String message = "annotation found in " + elem.getSimpleName() + " with complexity " + complexity.value(); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message, elem); } return true; // no further processing of this annotation type } Copyright © 2014 Accenture. All rights reserved. 18
Creating Files • jx.a.p.ProcessingEnvironment also provides access to the Filer utility that allows for easy file creation • Files are placed in the right folder as required by the compiler settings • Folder hierarchy matching the package name JavaFileObject jfo = processingEnv.getFiler() .createSourceFile(newClassQualifiedName); Writer writer = jfo.openWriter(); ...or... JavaFileObject jfo = processingEnv.getFiler() .createClassFile(newClassQualifiedName); OutputStream os = jfo.openOutputStream(); Copyright © 2014 Accenture. All rights reserved. 19
How the Compiler Knows? • Annotation Processors should be registered • The easiest way – leverage the standard services mechanism • Package the processors in a Jar file • Include file META-INF/services/javax.annotation.processing.Processor • Contents are the fully qualified names of all processors, one per line Copyright © 2014 Accenture. All rights reserved. 20
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 21
Running Annotation Processors • Multiple ways: • javac • Apache Maven builds • Continuous Integration builds • IDE • ... Copyright © 2014 Accenture. All rights reserved. 22
Running APs with javac • Use –proc:none when compiling Annotation Processors • When compiling the annotated classes: • Annotation types in classpath → $CP • Annotation Processor and dependencies in AP classpath → $APCP • Generated sources can be placed in a different folder → -s option javac -classpath $CP -processorpath $APCP sources -s generatedSourcesDir • Use -XprintProcessorInfo -XprintRounds and javac will print to console information about the processing (e.g. rounds) Copyright © 2014 Accenture. All rights reserved. 23
Running APs with Apache Maven • Annotation Type artifacts • Don’t have any special requirement • Annotation Processor artifacts • May add -proc:none to compiler arguments to disable Annotation processing during compilation • Artifacts using the annotations • Add AP artifacts as a dependency with compile scope • Add optionally compiler arguments for -Xprint... parameters Copyright © 2014 Accenture. All rights reserved. 24
Maven POM for Annotation Type <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerVersion>${java.version}</compilerVersion> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin></plugins></build> </project> Copyright © 2014 Accenture. All rights reserved. 25
Maven POM for Annotation Processor (I) <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.processors</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerVersion>${java.version}</compilerVersion> <source>${java.version}</source> <target>${java.version}</target> <compilerArgument>-proc:none</compilerArgument> </configuration> </plugin></plugins></build> ... Don’t run AP while building AP classes Copyright © 2014 Accenture. All rights reserved. 26
Maven POM for Annotation Processor (II) <dependencies> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> </project> • Use mvn install or mvn deploy to ensure that both artifacts are accessible to users Copyright © 2014 Accenture. All rights reserved. 27
Maven POM for Annotation users (I) <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.client</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> ... <compilerArgument> <XprintProcessorInfo/> <XprintRounds/> </compilerArgument> </configuration> </plugin></plugins></build> ... Copyright © 2014 Accenture. All rights reserved. 28
Maven POM for Annotation users (II) <dependencies> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.processors</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> </project> • Bug 224 in maven-compiler-plugin: logged messages during AP may not be shown in console Copyright © 2014 Accenture. All rights reserved. 29
Running APs with Continuous Integration • Generally, nothing to do while creating Maven jobs • I.e. Jenkins, Hudson, Travis, TeamCity... Copyright © 2014 Accenture. All rights reserved. 30
Running APs with Eclipse IDE • Configurable in detail in Java Compiler options • Whether to enable AP • Whether to enable AP automatically after changes in editors • Configure options sent to the AP • Configure target folder for generated sources • Configure AP classpath Copyright © 2014 Accenture. All rights reserved. 31
Running APs with NetBeans IDE • Configurable in detail in Java Compiler options (non-Maven only) • Whether to enable AP • Whether to enable AP automatically after changes in editors • Enable individual AP (or use auto-discovery) • Configure options sent to the AP Copyright © 2014 Accenture. All rights reserved. 32
Running APs with IntelliJ IDEA • Configurable in detail in Java Compiler options • Whether to enable AP • Enable individual AP (or use auto-discovery) • Configure options sent to the AP • Configure target folder for generated sources • Configure AP classpath Copyright © 2014 Accenture. All rights reserved. 33
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 34
Generating code – The BeanInfo Generator DEMO Copyright © 2014 Accenture. All rights reserved. 35
Generating code in Screenshots Copyright © 2014 Accenture. All rights reserved. 36
Generating code in Screenshots Copyright © 2014 Accenture. All rights reserved. 37
Generating code in Screenshots Copyright © 2014 Accenture. All rights reserved. 38
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 39
Generating code using APs and Velocity • While the previous example is simple... • ...As soon as complexity grows, it may become a mess • Designing a generator in that way is not recommended • Error prone • Hard to write, test and maintain • Model and view are highly coupled • A different approach is needed → Let’s use a template engine Copyright © 2014 Accenture. All rights reserved. 40
Generating code using APs and Velocity • Why Apache Velocity? • Good balance between power/flexibility and added complexity • Older but rock solid and feature rich • Documentation, examples, community • Other options • Eclipse Java Emitter Templates → Harder to integrate with javac • FreeMarker → Still in active development • Thymeleaf → More modern (2011+), used in Spring framework examples Copyright © 2014 Accenture. All rights reserved. 41
Generating code using APs and Velocity • Follow this high-level approach: 1. Read the model from source code • Mix information contained in Annotations with information already in the source • Store information in data structures that are easy to use 2. Populate derived attributes 3. Set up the template (don’t forget to pass the model as a parameter) 4. Generated code is ready Read model Derived attributes Set up template Generate! Copyright © 2014 Accenture. All rights reserved. 42
The BeanInfo Generator – Revisited DEMO Copyright © 2014 Accenture. All rights reserved. 43
The BeanInfo Generator – Revisited Copyright © 2014 Accenture. All rights reserved. 44
The BeanInfo Generator – Revisited Copyright © 2014 Accenture. All rights reserved. 45
The BeanInfo Generator – Revisited Easy access to model attributes Iterators, conditional operators, etc. Copyright © 2014 Accenture. All rights reserved. 46
The BeanInfo Generator – Revisited Copyright © 2014 Accenture. All rights reserved. 47
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 48
Going Forward – Bytecode Manipulation • The method described during the session, although direct and straightforward in concept, can only generate new sources • When the target is to modify existing classes (enhancing), a different approach is needed: • Work directly with javac API – for example Project Lombok • Bytecode manipulation with third-party libraries as ASM, cglib or Javassist – for example Datanucleus • Pros: exquisite level of control over the bytecodes • Cons: mastering bytecodes and the compiler API is not an easy task Copyright © 2014 Accenture. All rights reserved. 49
Project Lombok example lombok.javac.handlers.JavacHandlerUtil class: This is just a portion of the list of imports Highly coupled with the compiler API Copyright © 2014 Accenture. All rights reserved. 50
Project Lombok example lombok.javac.handlers.HandleGetter class: Not immediate to grasp Requires mastery of the compiler API Hard navigation through the AST (abstract syntax tree) of the existing class Copyright © 2014 Accenture. All rights reserved. 51
Datanucleus example org.datanucleus.enhancer.EnhancerProcessor class: First, locate the .class files Classes are already compiled when the AP is executed in each round Copyright © 2014 Accenture. All rights reserved. 52
Datanucleus example o.dn.enhancer.asm.JdoPropertyGetterAdapter class: To modify classes, it is required to think in bytecodes Copyright © 2014 Accenture. All rights reserved. 53
Agenda • Annotations in the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 54
Summary • Annotation Processors facilitates generation of source code • Also configuration files or deployment information • Seamless integration with the Java compiler, build tools and IDEs • No need to tweak with complex build processes • Generated code immediately available in the IDE • Recommended to be used along with template engines • Key for managing complexity of generators under control • Easier to create, test and maintain • Cannot be used for modifying existing classes • If needed, consider using a bytecode manipulation library Copyright © 2014 Accenture. All rights reserved. 55
Q & A Many thanks for attending! @_deors http://deors.wordpress.com Copyright © 2014 Accenture. All rights reserved. 56

JavaOne 2014 - CON2013 - Code Generation in the Java Compiler: Annotation Processors Do the Hard Work

  • 1.
    Code Generation inthe Java Compiler Annotation Processors Do the Hard Work JavaOne Conference – CON2013 – October 2014 Copyright © 2014 Accenture. All rights reserved.
  • 2.
    Code Generation inthe Java Compiler Objectives for the session: • Introduce Annotations and Annotation Processors • Learn how to create Annotation Processors • Learn how to use Annotation Processors to generate source code • Connect Annotation Processors with external generation engines • Integration with IDEs and build automation tools • With lots of examples and source code Copyright © 2014 Accenture. All rights reserved. 1
  • 3.
    About the Speaker Jorge Hidalgo @_deors Accenture, Malaga (Spain) Senior Technology Architect Java Lead at the Accenture Delivery Center in Spain 15 years of IT professional experience across industries From time to time writing a blog called Dr. MacPhail’s Trance: http://deors.wordpress.com Father of two children, husband, whistle player, video gamer, sci-fi junkie, Raspberry Pi fan... Copyright © 2014 Accenture. All rights reserved. 2
  • 4.
    Code Generation –Why? • To not repeat the same tasks again and again • To reduce the burden of boilerplate code • To standardize code patterns, follow common idioms • To ensure that best practices are applied • To improve the adherence to coding standards (naming, style) • ... PRODUCTIVITY QUALITY PREDICTABILITY Copyright © 2014 Accenture. All rights reserved. 3
  • 5.
    Poll #1 •Please raise your hands if you are familiar with Annotations, know how to use them or are even capable of writing Annotation Types Copyright © 2014 Accenture. All rights reserved. 4
  • 6.
    Poll #2 •Please raise your hands if you are familiar with Annotation Processors, their capabilities or know how to write new ones Copyright © 2014 Accenture. All rights reserved. 5
  • 7.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 6
  • 8.
    Annotations in theJava Language • Annotations were first introduced in Java 5 • Add metadata capabilities to the Java language: • Build/deployment information • Configuration properties • Compiler behavior • Quality checks • Dependency injection • Persistence mapping • ... Copyright © 2014 Accenture. All rights reserved. 7
  • 9.
    Annotations in theJava Language • Annotations always appear before the annotated piece of code • Annotations can ‘decorate’... • Packages • Types (classes, interfaces, enums, annotation types) • Variables (class, instance and local variables) • Constructors, methods and their parameters • Generic type parameter (since Java 8) • Any type use (since Java 8) • Can be grouped, nested, repeated... very powerful! Map<@NonNull String, @NonEmpty List<@Readonly Document>> docStore; Copyright © 2014 Accenture. All rights reserved. 8
  • 10.
    Annotations in theJava Language • Annotations may be used just as a ‘marker’ @NonNull String email; • They may contain name-value pairs, and arrays @Author(name = "Albert", created = "17/09/2010", revision = 3, reviewers = {"George", "Fred"}) public class SomeClass {...} • Can be defined with default values, and then omitted when used • When it has only one attribute named value, it can be omitted, too @DatabaseTable(“MY_TABLE”) public class MyTable {...} Copyright © 2014 Accenture. All rights reserved. 9
  • 11.
    Create an AnnotationType • A special type of interface public @interface Author { String name(); String created(); int revision() default 1; String[] reviewers() default {}; } • Only primitives, enum types, annotation types, String, Class and arrays of them are allowed as elements • May be annotated itself, i.e. to define the retention policy or targets @Retention(RetentionPolicy.SOURCE) @Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE}) public @interface Author {...} Copyright © 2014 Accenture. All rights reserved. 10
  • 12.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 11
  • 13.
    Annotation Processors Thisis cool but I can add metadata information with Javadocs, so what’s the buzz? /** * My Class description. * @author jorge.hidalgo * @version 1.0 * @deprecated Use MyNewClass instead */ Copyright © 2014 Accenture. All rights reserved. 12
  • 14.
    Annotation Processors •Annotations are first-class citizens in the Java language • Formalized in the Java Language Specification • Readable at run time: Class.getAnnotations() Class.getAnnotationsByType(Class<A>) Class.getDeclaredAnnotations() Class.getDeclaredAnnotationsByType(Class<A>) • Can trigger custom actions at compile time managed by Annotation Processors! Copyright © 2014 Accenture. All rights reserved. 13
  • 15.
    Annotation Processors •When first introduced in Java 5, the Annotation Processing API was not standard • A standalone tool, apt, was needed to process annotations • Mirror API distributed in com.sun.mirror packages • Starting with Java 6, standardized through JSR-269(1) • apt, although still available for standalone execution, was seamlessly integrated into the Java compiler, javac • Annotation Processing API distributed in javax.lang.model packages • Since Java 8, apt is no longer available in the JDK (1) JSR-269, Pluggable Annotation Processing API, can be browsed online here. Copyright © 2014 Accenture. All rights reserved. 14
  • 16.
    Annotation Processing API • Annotation Processor: • Implements javax.annotation.processing.Processor • Or extends javax.annotation.processing.AbstractProcessor • May use three annotations to configure itself: • jx.a.p.SupportedAnnotationTypes – Used to flag which Annotation Types are managed by the processor • jx.a.p.SupportedSourceVersion – Used to flag the latest Java source level supported by the processor • jx.a.p.SupportedOptions – Used to register custom parameters that may be passed through the command line • TL;DR – Implement the process() method Copyright © 2014 Accenture. All rights reserved. 15
  • 17.
    Hello Multiverse Processor @Documented @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Complexity { ComplexityLevel value() default ComplexityLevel.MEDIUM; } public enum ComplexityLevel { VERY_SIMPLE, SIMPLE, MEDIUM, COMPLEX, VERY_COMPLEX; } @SupportedAnnotationTypes("deors.demos.annotations.base.Complexity") @SupportedSourceVersion(SourceVersion.RELEASE_8) public class ComplexityProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return true; } } Tell the compiler this processor actually handled the annotation Copyright © 2014 Accenture. All rights reserved. 16
  • 18.
    Rounds and environment • Annotation processing happens in ‘rounds’ • In each round, a subset of sources are compiled, and then processors matching the annotations found on those sources are called • Processing ends when no more sources/annotations are pending • Processors may claim all annotation types with a wildcard • process() method has two parameters: • Set<? extends jx.lang.model.element.TypeElement> – subset of annotations being processed • jx.a.p.RoundEnvironment – access to information about the current and previous round Copyright © 2014 Accenture. All rights reserved. 17
  • 19.
    Rounds and environment • When extending jx.a.p.AbstractProcessor, there is available an instance variable of type jx.a.p.ProcessingEnvironment with access to a specialized logging tool, the Messager @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element elem : roundEnv.getElementsAnnotatedWith(Complexity.class)) { Complexity complexity = elem.getAnnotation(Complexity.class); String message = "annotation found in " + elem.getSimpleName() + " with complexity " + complexity.value(); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message, elem); } return true; // no further processing of this annotation type } Copyright © 2014 Accenture. All rights reserved. 18
  • 20.
    Creating Files •jx.a.p.ProcessingEnvironment also provides access to the Filer utility that allows for easy file creation • Files are placed in the right folder as required by the compiler settings • Folder hierarchy matching the package name JavaFileObject jfo = processingEnv.getFiler() .createSourceFile(newClassQualifiedName); Writer writer = jfo.openWriter(); ...or... JavaFileObject jfo = processingEnv.getFiler() .createClassFile(newClassQualifiedName); OutputStream os = jfo.openOutputStream(); Copyright © 2014 Accenture. All rights reserved. 19
  • 21.
    How the CompilerKnows? • Annotation Processors should be registered • The easiest way – leverage the standard services mechanism • Package the processors in a Jar file • Include file META-INF/services/javax.annotation.processing.Processor • Contents are the fully qualified names of all processors, one per line Copyright © 2014 Accenture. All rights reserved. 20
  • 22.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 21
  • 23.
    Running Annotation Processors • Multiple ways: • javac • Apache Maven builds • Continuous Integration builds • IDE • ... Copyright © 2014 Accenture. All rights reserved. 22
  • 24.
    Running APs withjavac • Use –proc:none when compiling Annotation Processors • When compiling the annotated classes: • Annotation types in classpath → $CP • Annotation Processor and dependencies in AP classpath → $APCP • Generated sources can be placed in a different folder → -s option javac -classpath $CP -processorpath $APCP sources -s generatedSourcesDir • Use -XprintProcessorInfo -XprintRounds and javac will print to console information about the processing (e.g. rounds) Copyright © 2014 Accenture. All rights reserved. 23
  • 25.
    Running APs withApache Maven • Annotation Type artifacts • Don’t have any special requirement • Annotation Processor artifacts • May add -proc:none to compiler arguments to disable Annotation processing during compilation • Artifacts using the annotations • Add AP artifacts as a dependency with compile scope • Add optionally compiler arguments for -Xprint... parameters Copyright © 2014 Accenture. All rights reserved. 24
  • 26.
    Maven POM forAnnotation Type <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerVersion>${java.version}</compilerVersion> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin></plugins></build> </project> Copyright © 2014 Accenture. All rights reserved. 25
  • 27.
    Maven POM forAnnotation Processor (I) <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.processors</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerVersion>${java.version}</compilerVersion> <source>${java.version}</source> <target>${java.version}</target> <compilerArgument>-proc:none</compilerArgument> </configuration> </plugin></plugins></build> ... Don’t run AP while building AP classes Copyright © 2014 Accenture. All rights reserved. 26
  • 28.
    Maven POM forAnnotation Processor (II) <dependencies> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> </project> • Use mvn install or mvn deploy to ensure that both artifacts are accessible to users Copyright © 2014 Accenture. All rights reserved. 27
  • 29.
    Maven POM forAnnotation users (I) <project ...> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.client</artifactId> <version>1.0-SNAPSHOT</version> <properties><java.version>1.8</java.version></properties> <build><plugins><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> ... <compilerArgument> <XprintProcessorInfo/> <XprintRounds/> </compilerArgument> </configuration> </plugin></plugins></build> ... Copyright © 2014 Accenture. All rights reserved. 28
  • 30.
    Maven POM forAnnotation users (II) <dependencies> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> <groupId>deors.demos</groupId> <artifactId>deors.demos.annotations.base.processors</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> </dependencies> </project> • Bug 224 in maven-compiler-plugin: logged messages during AP may not be shown in console Copyright © 2014 Accenture. All rights reserved. 29
  • 31.
    Running APs withContinuous Integration • Generally, nothing to do while creating Maven jobs • I.e. Jenkins, Hudson, Travis, TeamCity... Copyright © 2014 Accenture. All rights reserved. 30
  • 32.
    Running APs withEclipse IDE • Configurable in detail in Java Compiler options • Whether to enable AP • Whether to enable AP automatically after changes in editors • Configure options sent to the AP • Configure target folder for generated sources • Configure AP classpath Copyright © 2014 Accenture. All rights reserved. 31
  • 33.
    Running APs withNetBeans IDE • Configurable in detail in Java Compiler options (non-Maven only) • Whether to enable AP • Whether to enable AP automatically after changes in editors • Enable individual AP (or use auto-discovery) • Configure options sent to the AP Copyright © 2014 Accenture. All rights reserved. 32
  • 34.
    Running APs withIntelliJ IDEA • Configurable in detail in Java Compiler options • Whether to enable AP • Enable individual AP (or use auto-discovery) • Configure options sent to the AP • Configure target folder for generated sources • Configure AP classpath Copyright © 2014 Accenture. All rights reserved. 33
  • 35.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 34
  • 36.
    Generating code –The BeanInfo Generator DEMO Copyright © 2014 Accenture. All rights reserved. 35
  • 37.
    Generating code inScreenshots Copyright © 2014 Accenture. All rights reserved. 36
  • 38.
    Generating code inScreenshots Copyright © 2014 Accenture. All rights reserved. 37
  • 39.
    Generating code inScreenshots Copyright © 2014 Accenture. All rights reserved. 38
  • 40.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 39
  • 41.
    Generating code usingAPs and Velocity • While the previous example is simple... • ...As soon as complexity grows, it may become a mess • Designing a generator in that way is not recommended • Error prone • Hard to write, test and maintain • Model and view are highly coupled • A different approach is needed → Let’s use a template engine Copyright © 2014 Accenture. All rights reserved. 40
  • 42.
    Generating code usingAPs and Velocity • Why Apache Velocity? • Good balance between power/flexibility and added complexity • Older but rock solid and feature rich • Documentation, examples, community • Other options • Eclipse Java Emitter Templates → Harder to integrate with javac • FreeMarker → Still in active development • Thymeleaf → More modern (2011+), used in Spring framework examples Copyright © 2014 Accenture. All rights reserved. 41
  • 43.
    Generating code usingAPs and Velocity • Follow this high-level approach: 1. Read the model from source code • Mix information contained in Annotations with information already in the source • Store information in data structures that are easy to use 2. Populate derived attributes 3. Set up the template (don’t forget to pass the model as a parameter) 4. Generated code is ready Read model Derived attributes Set up template Generate! Copyright © 2014 Accenture. All rights reserved. 42
  • 44.
    The BeanInfo Generator– Revisited DEMO Copyright © 2014 Accenture. All rights reserved. 43
  • 45.
    The BeanInfo Generator– Revisited Copyright © 2014 Accenture. All rights reserved. 44
  • 46.
    The BeanInfo Generator– Revisited Copyright © 2014 Accenture. All rights reserved. 45
  • 47.
    The BeanInfo Generator– Revisited Easy access to model attributes Iterators, conditional operators, etc. Copyright © 2014 Accenture. All rights reserved. 46
  • 48.
    The BeanInfo Generator– Revisited Copyright © 2014 Accenture. All rights reserved. 47
  • 49.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 48
  • 50.
    Going Forward –Bytecode Manipulation • The method described during the session, although direct and straightforward in concept, can only generate new sources • When the target is to modify existing classes (enhancing), a different approach is needed: • Work directly with javac API – for example Project Lombok • Bytecode manipulation with third-party libraries as ASM, cglib or Javassist – for example Datanucleus • Pros: exquisite level of control over the bytecodes • Cons: mastering bytecodes and the compiler API is not an easy task Copyright © 2014 Accenture. All rights reserved. 49
  • 51.
    Project Lombok example lombok.javac.handlers.JavacHandlerUtil class: This is just a portion of the list of imports Highly coupled with the compiler API Copyright © 2014 Accenture. All rights reserved. 50
  • 52.
    Project Lombok example lombok.javac.handlers.HandleGetter class: Not immediate to grasp Requires mastery of the compiler API Hard navigation through the AST (abstract syntax tree) of the existing class Copyright © 2014 Accenture. All rights reserved. 51
  • 53.
    Datanucleus example org.datanucleus.enhancer.EnhancerProcessorclass: First, locate the .class files Classes are already compiled when the AP is executed in each round Copyright © 2014 Accenture. All rights reserved. 52
  • 54.
    Datanucleus example o.dn.enhancer.asm.JdoPropertyGetterAdapterclass: To modify classes, it is required to think in bytecodes Copyright © 2014 Accenture. All rights reserved. 53
  • 55.
    Agenda • Annotationsin the Java language • Annotation Processors • Running Annotation Processors • Generating source code using Annotation Processors • Generating source code using APs and Apache Velocity • Going forward: Modifying existing bytecodes • Summary • Q & A Copyright © 2014 Accenture. All rights reserved. 54
  • 56.
    Summary • AnnotationProcessors facilitates generation of source code • Also configuration files or deployment information • Seamless integration with the Java compiler, build tools and IDEs • No need to tweak with complex build processes • Generated code immediately available in the IDE • Recommended to be used along with template engines • Key for managing complexity of generators under control • Easier to create, test and maintain • Cannot be used for modifying existing classes • If needed, consider using a bytecode manipulation library Copyright © 2014 Accenture. All rights reserved. 55
  • 57.
    Q & A Many thanks for attending! @_deors http://deors.wordpress.com Copyright © 2014 Accenture. All rights reserved. 56