Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java Annotation Processing: A Beginner Walkthrough

1,804 views

Published on

Java Annotation is quite a handy tool and has the ample potential to make developer's life a lot easier(and exciting!). Learning and using custom Java Annotation Processor takes the power of Annotation even a class higher. This slide goes over a few fundamental things of an Annotation Processor to get someone started to write his/her own Annotation Processor in Java.

Key topics are,

- Java Annotation
- Usage of Annotation
- Custom Java Annotation
- Java Annotation Processor
- Usefulness of Annotation Processor
- Dive into the core of Annotation Processor
- Solve a validation problem with Custom Annotation Processor
- Get to know some exciting Annotation Processing tools that already exist

Published in: Software

Java Annotation Processing: A Beginner Walkthrough

  1. 1. Java Annotation Processing A Beginner Walkthrough Mahfuz Islam Bhuiyan Software Engineer, Genweb2
  2. 2. What’s Annotation? ● Provide meta-data for Java code ● Can describe usage of an element, e.g. @Deprecated ● Can describe the nature of an element, e.g. @WebService ● and many more
  3. 3. Built-in Java Annotations @Deprecated @Override @SuppressWarning
  4. 4. Custom Annotation public @interface MyAnnotation { // @interface tells Java that it’s a custom annotation String value(); String name(); int age(); String[] newNames(); }
  5. 5. Custom Annotation @MyAnnotation( value="Test123456", name=" Oveget ", age=37, newNames={"Rishi", "Farzana"} ) public class MyClass { }
  6. 6. Custom Annotation public @interface MyAnnotation { String value() default ""; String name() default " The Sufi "; int age(); String[] newNames(); }
  7. 7. Annotation Processing Trends ● Remove boilerplate ● Inject Source Code ● Validate Fields, Methods, Class etc
  8. 8. Annotation Processing Facts ● Part of javac ● Introduced in Java 5 ● Run at Compile Time(!) ● Own JVM ● Native Java code ● No Reflection(by default)
  9. 9. Java Reflection ● Makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time. ● Can instantiate new objects, invoke methods and get/set field values using reflection.
  10. 10. Java Reflections Method[] methods = MyObject.class.getMethods(); for(Method method : methods){ System.out.println("method = " + method.getName()); }
  11. 11. Java Reflections Class aClass = MyObject.class Field field = aClass.getField("someField"); MyObject objectInstance = new MyObject(); Object value = field.get(objectInstance); field.set(objetInstance, value);
  12. 12. @Retention @Retention(RetentionPolicy.RUNTIME) // Allows the annotation to be available at Runtime @Target({ElementType.METHOD}) public @interface MyAnnotation { // Yes, we can apply annotation over another annotation String value() default ""; }
  13. 13. Annotation Processing Limitations ● Generate only new files ● Can’t manipulate already existing files(But byte manipulation possible with sacrificing debugging capability)
  14. 14. Create Your Own Annotation Processor 1. Extends AbstractProcessor 2. Register the processor with javac
  15. 15. Extending Abstract Processor public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){} @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } @Override public Set<String> getSupportedAnnotationTypes() { } @Override public SourceVersion getSupportedSourceVersion() { } }
  16. 16. Extending Abstract Processor @SupportedSourceVersion(SourceVersion.latestSupported()) @SupportedAnnotationTypes({ // Set of full qualified annotation type names }) public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){ } @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } }
  17. 17. Extending Abstract Processor @SupportedSourceVersion(SourceVersion.latestSupported()) @SupportedAnnotationTypes({ // Set of full qualified annotation type names }) public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){ } // We need to get our hands dirty with following method @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } }
  18. 18. Register the Processor 1. Create a .jar file with our Annotation Processor Java file 2. Provide a special file called javax.annotation.processing.Processor located in META-INF/services in your .jar file 3. Within the javax.annotation.processing.Processor , there should be the fully qualified names of the processors contained in the Jar file(like, com.example. MyProcessor.class)
  19. 19. So, it’ll look like MyProcessor.jar => com => example => MyProcessor.class => META-INF => services => javax.annotation.processing.Processor
  20. 20. Validate a Class with Custom Annotation Processor
  21. 21. Annotation import com.example; public @interface ConstructorCheck{ }
  22. 22. Annotation Processor @SupportedSourceVersion(SourceVersion.latestSupported()) @SupportedAnnotationTypes({"com.example.ConstructorCheck"}) } public class MyProcessor extends AbstractProcessor { @Override public synchronized void init(ProcessingEnvironment env){ } @Override public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { } }
  23. 23. init ProcessingEnvironment processingEnv; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); this.processingEnv = processingEnv; }
  24. 24. ProcessingEnvironment ● getElementUtils => Elements ● getTypeUtils => Types ● getFiler => Filer ● getMessager => Messager
  25. 25. Element ● Is not a class per se ! ● Contains value that can be of Class, Interface etc
  26. 26. Element public class User{ // TypeElement private String name; // VariableElement private Person personObj; // VariableElement public User(){} // ExecutableElement public boolean isUserHasNID(){ // ExecutableElement /*...*/ } }
  27. 27. TypeMirror ● Provide some meta data about Element ● Get to know the class inheritance hierarchy, for instance
  28. 28. process @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { checkEntityAnnotatedElements(roundEnv); return false; // true if we want to stop processor’s further execution }
  29. 29. private void checkEntityAnnotatedElements(RoundEnvironment roundEnv) { Set <? extends Element > entityAnnotated = roundEnv.getElementsAnnotatedWith(CheckConstructor. class); for (TypeElement typeElement: ElementFilter.typesIn(entityAnnotated)) { for (ExecutableElement constructor: ElementFilter.constructorsIn(typeElement. getEnclosedElements())) { List <? extends VariableElement > parameters = constructor.getParameters(); if (parameters.isEmpty()) return; } AnnotationMirror entityAnnotation = getAnnotation(typeElement, entityType.type); processingEnv.getMessager().printMessage(Kind.ERROR, "missing no argument constructor", typeElement, entityAnnotation); } }
  30. 30. Automatic Source Code Generating Tool
  31. 31. JavaPoet ● JavaPoet is a API for generating java source files. ● It can be useful when doing things such as annotation processing or interacting with metadata files.
  32. 32. JavaPoet Here goes a plain simple java class package com.example.helloworld; public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } }
  33. 33. JavaPoet With JavaPoet, it’ll look like this. MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class).addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!").build(); TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL).addMethod(main).build(); JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld).build(); javaFile.writeTo(System.out)
  34. 34. Some Cool Annotation Based Tools
  35. 35. Project Lombok ● Project Lombok greatly reduces the number of lines of boilerplate code
  36. 36. Dagger 2 ● Dagger 2 is a fork from Dagger 1 under heavy development by Google ● Dependency Injection design pattern without the burden of writing the boilerplate ● No reflection at all ● Achieved 13% performance boost over Dagger 1
  37. 37. Butter Knife ● Butter Knife injects views on Android ● Reduce boilerplate codes ● Support Resource and Event binding too
  38. 38. Butter Knife class ExampleActivity extends Activity { TextView title, subtitle; EditText inputTitle, inputSubTitle; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); title = (TextView)findViewById(R.id.title); subtitle = (TextView)findViewById(R.id.subtitle); inputTitle = (EditText)findViewById(R.id.inputTitle); inputSubtitle = (EditText)findViewById(R.id.inputSubTitle); } }
  39. 39. Butter Knife class ExampleActivity extends Activity { @Bind(R.id.title) TextView title; @Bind(R.id.subtitle) TextView subtitle; @Bind(R.id.subtitle) EditText inputTitle; @Bind(R.id.subtitle) EditText inputSubtitle; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.bind(this); } }
  40. 40. References ● Annotation Processing 101 ● Code Generation Using Annotation Processor in Java ● Writing Annotation Processors to aid your development process ● Android Tech Talk: Annotation Processing Boilerplate Destruction ● Java Annotation Processor Tutorial ● Java Annotations ● Official Java Annotation Processor Documentation
  41. 41. @thankYou

×