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
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
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.
10. 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.
12. Java Reflections
Class aClass = MyObject.class
Field field = aClass.getField("someField");
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objetInstance, value);
13. @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 "";
}
14. Annotation Processing Limitations
● Generate only new files
● Can’t manipulate already existing files(But byte manipulation possible with
sacrificing debugging capability)
15. Create Your Own Annotation Processor
1. Extends AbstractProcessor
2. Register the processor with javac
16.
17. 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() { }
}
20. 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)
21. So, it’ll look like
MyProcessor.jar
=> com
=> example
=> MyProcessor.class
=> META-INF
=> services
=> javax.annotation.processing.Processor
27. Element
● Is not a class per se !
● Contains value that can be of Class, Interface etc
28.
29. Element
public class User{ // TypeElement
private String name; // VariableElement
private Person personObj; // VariableElement
public User(){} // ExecutableElement
public boolean isUserHasNID(){ // ExecutableElement
/*...*/
}
}
30. TypeMirror
● Provide some meta data about Element
● Get to know the class inheritance hierarchy, for instance
31. 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
}
32. 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);
}
}
34. 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.
35. 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!");
}
}
41. 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
42. Butter Knife
● Butter Knife injects views on Android
● Reduce boilerplate codes
● Support Resource and Event binding too