SlideShare a Scribd company logo
Annotation
Processing
Tim
About me
Tim / Jintin

Android / iOS developer

Senior Software Engineer 

@ Carousell

https://github.com/Jintin

https://medium.com/@Jintin
How to write
flawless code?
Annotation Processing
Annotation Processing
Annotation Processing
Don’t write ANY code
Do write LESS code
“Annotation Processing is a tool we
can use to help us generate code in
compile time by labeling Annotations
inside our source code.”
Pros & Cons
+ Less boilerplate code

+ No Runtime Error

- Block incremental build

- Kotlin 1.3.30+

- Gradle 4.7+
- Compile overhead
One more thing…
One more inch…
How does Annotation
Processing work?
How we use it
dependencies {

implementation 'com.google.dagger:dagger:2.x'

kapt ‘com.google.dagger:dagger-compiler:2.x'

}
kapt stands for 

Kotlin annotation processing tool
Module structure
Library module (optional)

Processor(compiler) module

Annotation module
Annotation
Annotation
Attributes

Targets

Retention
Attribute
@GET(“XXX_Value")

Observable getAPI();

@Component(modules = {

AModule.class,

BModule.class,

CModule.class})

public interface MyComponent {}
Attribute
@Target(METHOD)

@Retention(RUNTIME)

public @interface GET {

String value() default "";

}

@Retention(RUNTIME)

@Target(TYPE)

public @interface Component {

Class<?>[] modules() default {};

Class<?>[] dependencies() default {};

}
Attribute
Primitive types (int, long, etc.)

String

Classes (Foo::class)

Enums

Other annotations

Arrays of the types listed above.
Annotation
Attributes

Targets

Retention
Target
@Retention(RetentionPolicy.RUNTIME)

@Target(value={CONSTRUCTOR, FIELD,
LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER,
TYPE})

public @interface Deprecated {}
Annotation
Attributes

Targets

Retention
Retention
@Target(ElementType.METHOD)

@Retention(SOURCE)

public @interface Override {}

@Target({ METHOD, CONSTRUCTOR, FIELD })

@Retention(RUNTIME)

public @interface Inject {}
Retention
public enum RetentionPolicy {

/* only exist before compile finish. */
SOURCE,
/* recorded in the class file by the compiler but need not
be retained by the VM at run time. */
CLASS,
/* to be recorded in the class file and can be used at run
time, so they may be read reflectively. */
RUNTIME
}
Retention
public enum RetentionPolicy {

/* only exist before compile finish. */
SOURCE,
/* recorded in the class file by the compiler but need not
be retained by the VM at run time. */
CLASS,
/* to be recorded in the class file and can be used at run
time, so they may be read reflectively. */
RUNTIME
}
Retention
public enum RetentionPolicy {

/* only exist before compile finish. */
SOURCE,
/* recorded in the class file by the compiler but need not
be retained by the VM at run time. */
CLASS,
/* to be recorded in the class file and can be used at run
time, so they may be read reflectively. */
RUNTIME
}
Retention
public enum RetentionPolicy {

/* only exist before compile finish. */
SOURCE,
/* recorded in the class file by the compiler but need not
be retained by the VM at run time. */
CLASS,
/* to be recorded in the class file and can be used at run
time, so they may be read reflectively. */
RUNTIME
}
Processor module
Only used in compile phase.

Not include in final Jar/Apk.

Can contain several Processors.
Hook
AutoService Hook
@AutoService(Processor::class)

class AdapterProcessor : Processor()



dependencies {

implementation ‘com.google.auto.service:auto-service:1.X’

}
public interface Processor {

/** Initializes with the processing environment. */
void init(ProcessingEnvironment processingEnv);

/** Returns the target the annotation types to process. */
Set<String> getSupportedAnnotationTypes();

/** Processes a set of annotation on type elements. */
boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv);

…
}
Processor
public interface Processor {

/** Initializes with the processing environment. */
void init(ProcessingEnvironment processingEnv);

/** Returns the target the annotation types to process. */
Set<String> getSupportedAnnotationTypes();

/** Processes a set of annotation on type elements. */
boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv);

…
}
Processor
public interface Processor {

/** Initializes with the processing environment. */
void init(ProcessingEnvironment processingEnv);

/** Returns the target the annotation types to process. */
Set<String> getSupportedAnnotationTypes();

/** Processes a set of annotation on type elements. */
boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv);

…
}
Processor
public interface Processor {

/** Initializes with the processing environment. */
void init(ProcessingEnvironment processingEnv);

/** Returns the target the annotation types to process. */
Set<String> getSupportedAnnotationTypes();

/** Processes a set of annotation on type elements. */
boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv);

…
}
Processor
Element
Unit of code element.

- PackageElement: Package

- TypeElement: Class, Interface

- ExecutableElement: Method, Constructor
@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

for (Element element : 

roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {

if (element.getKind() != ElementKind.INTERFACE) {

error("Only interface can be used with MyAnnotation", element);

return true;

}

TypeElement typeElement = (TypeElement) element;

typeElement.getInterfaces();

typeElement.getSuperclass();

typeElement.getSimpleName();

MyAnnotation anno = element.getAnnotation(MyAnnotation.class);

/** Custom logic to build the relation graph and generate the file*/
}

return true;

}
@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

for (Element element : 

roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {

if (element.getKind() != ElementKind.INTERFACE) {

error("Only interface can be used with MyAnnotation", element);

return true;

}

TypeElement typeElement = (TypeElement) element;

typeElement.getInterfaces();

typeElement.getSuperclass();

typeElement.getSimpleName();

MyAnnotation anno = element.getAnnotation(MyAnnotation.class);

/** Custom logic to build the relation graph and generate the file*/
}

return true;

}
@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

for (Element element : 

roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {

if (element.getKind() != ElementKind.INTERFACE) {

error("Only interface can be used with MyAnnotation", element);

return true;

}

TypeElement typeElement = (TypeElement) element;

typeElement.getInterfaces();

typeElement.getSuperclass();

typeElement.getSimpleName();

MyAnnotation anno = element.getAnnotation(MyAnnotation.class);

/** Custom logic to build the relation graph and generate the file*/
}

return true;

}
@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

for (Element element : 

roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {

if (element.getKind() != ElementKind.INTERFACE) {

error("Only interface can be used with MyAnnotation", element);

return true;

}

TypeElement typeElement = (TypeElement) element;

typeElement.getInterfaces();

typeElement.getSuperclass();

typeElement.getSimpleName();

MyAnnotation anno = element.getAnnotation(MyAnnotation.class);

/** Custom logic to build the relation graph and generate the file*/
}

return true;

}
@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

for (Element element : 

roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {

if (element.getKind() != ElementKind.INTERFACE) {

error("Only interface can be used with MyAnnotation", element);

return true;

}

TypeElement typeElement = (TypeElement) element;

typeElement.getInterfaces();

typeElement.getSuperclass();

typeElement.getSimpleName();

MyAnnotation anno = element.getAnnotation(MyAnnotation.class);

/** Custom logic to build the relation graph and generate the file*/
}

return true;

}
How to create file?
Filer
Get from ProcessingEnvironment

Generate file under build folder
Filer
@Override

public synchronized void init(ProcessingEnvironment env) {

super.init(env);

filer = env.getFiler();

}

@Override

public boolean process(Set<? extends TypeElement> set, 

RoundEnvironment roundEnv) {

…
filer.createSourceFile(“NewFile", element);

}
How to create code?
JavaPoet/KotlinPoet
Provide simple API to generate Java/Kotlin file

Both Square open source projects

Over 8000 stars in total
MethodSpec main = MethodSpec.methodBuilder("main")

.build();
JavaPoet
MethodSpec main = MethodSpec.methodBuilder("main")

.build();



void main() {

}
JavaPoet
MethodSpec main = MethodSpec.methodBuilder("main")

.addParameter(String[].class, "args")

.build();



void main(String[] args) {

}
JavaPoet
MethodSpec main = MethodSpec.methodBuilder("main")

.addParameter(String[].class, "args")

.addStatement("$T.out.println($S)", System.class, 

"Hello, JavaPoet!")

.build();



void main(String[] args) {

System.out.println("Hello, JavaPoet!");

}
JavaPoet
MethodSpec main = MethodSpec.methodBuilder("main")

.addParameter(String[].class, "args")

.addStatement("$T.out.println($S)", System.class, 

“Hello, JavaPoet!")

.addModifiers(Modifier.PUBLIC, Modifier.STATIC)

.build();



public static void main(String[] args) {

System.out.println("Hello, JavaPoet!");

}
JavaPoet
TypeSpec helloWorld = TypeSpec.classBuilder("HellowWorld")

.addMethod(MethodSpec.{…})

.addModifiers(Modifier.PUBLIC, Modifier.FINAL)

.build();

public final class HelloWorld {

public static void main(String[] args) {

System.out.println("Hello, JavaPoet!");

}

}
JavaPoet
Tips
Find the boilerplate of daily work, eg: findViewById,
dependency graph, deep link, etc.

Find the pattern and define each component.

Label each component with annotation.

Create processor to generate code and link each
component.
Example
Factory
public interface Animal {}

public class Cat implements Animal {}

public class Dog implements Animal {}

public final class AnimalFactory {

public static Animal createAnimal(String type) {

switch(type) {

case "cat": return new Cat();

case "dog": return new Dog();

}

throw new RuntimeException("not support type");

}

}
Factory
public interface Animal {}

public class Cat implements Animal {}

public class Dog implements Animal {}

public final class AnimalFactory {

public static Animal createAnimal(String type) {

switch(type) {

case "cat": return new Cat();

case "dog": return new Dog();

}

throw new RuntimeException("not support type");

}

}
Auto Generate?
@AutoFactory

public interface Animal {}



@AutoElement(AnimalTags.CAT)

public class Cat implements Animal {}

@AutoElement(AnimalTags.DOG)

public class Dog implements Animal {}

// https://github.com/Jintin/AutoFactory
Example 2
1 ViewHolder
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);
}

}

}
Add ViewHolder
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

protected static final int TYPE_HOLDER2 = 2;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

case TYPE_HOLDER2: {

return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);
}

}

}
Add more ViewHolder
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

protected static final int TYPE_HOLDER2 = 2;

protected static final int TYPE_HOLDER3 = 3;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

case TYPE_HOLDER2: {

return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false));

}

case TYPE_HOLDER3: {

return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);
}

}

}
Even more ViewHolders
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

protected static final int TYPE_HOLDER2 = 2;

protected static final int TYPE_HOLDER3 = 3;

protected static final int TYPE_HOLDER4 = 4;

protected static final int TYPE_HOLDER5 = 5;

protected static final int TYPE_HOLDER6 = 6;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

case TYPE_HOLDER2: {

return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false));

}

case TYPE_HOLDER3: {

return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false));

}

case TYPE_HOLDER4: {

return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false));

}

case TYPE_HOLDER5: {

return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false));

}

case TYPE_HOLDER6: {

return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);

}

}

}
Even more Adapters
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

protected static final int TYPE_HOLDER2 = 2;

protected static final int TYPE_HOLDER3 = 3;

protected static final int TYPE_HOLDER4 = 4;

protected static final int TYPE_HOLDER5 = 5;

protected static final int TYPE_HOLDER6 = 6;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

case TYPE_HOLDER2: {

return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false));

}

case TYPE_HOLDER3: {

return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false));

}

case TYPE_HOLDER4: {

return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false));

}

case TYPE_HOLDER5: {

return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false));

}

case TYPE_HOLDER6: {

return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);

}

}

}

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

protected static final int TYPE_HOLDER1 = 1;

protected static final int TYPE_HOLDER2 = 2;

protected static final int TYPE_HOLDER3 = 3;

protected static final int TYPE_HOLDER4 = 4;

protected static final int TYPE_HOLDER5 = 5;

protected static final int TYPE_HOLDER6 = 6;

@Override

public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

switch (viewType) {

case TYPE_HOLDER1: {

return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false));

}

case TYPE_HOLDER2: {

return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false));

}

case TYPE_HOLDER3: {

return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false));

}

case TYPE_HOLDER4: {

return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false));

}

case TYPE_HOLDER5: {

return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false));

}

case TYPE_HOLDER6: {

return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false));

}

default: throw new RuntimeException("Not support type" + viewType);

}

}

}
Annotation Processing
@BindHolder(Holder1.class)

@BindHolder(Holder2.class)

@BindHolder(Holder3.class, R.layout.view3)

@BindHolder(Holder4.class, R.layout.view4)

public class MyAdapter extends MyAdapterHelper {}

@BindLayout(R.layout.item_holder1)

class ViewHolder1 extends RecyclerView.ViewHolder {}

@BindLayout(R.layout.item_holder2)

class ViewHolder2 extends RecyclerView.ViewHolder {}

// https://github.com/Jintin/ComposeAdapter
Reference
https://kotlinlang.org/docs/reference/annotations.html

https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/
Processor.html

https://docs.oracle.com/javase/8/docs/api/javax/lang/model/element/
Element.html

https://kotlinlang.org/docs/reference/kapt.html

https://github.com/gradle/gradle/blob/master/subprojects/docs/src/docs/
userguide/java_plugin.adoc#state-of-support-in-popular-annotation-
processors

https://medium.com/@jintin/annotation-processing-in-java-3621cb05343a
Reference
https://github.com/google/auto/tree/master/service

https://github.com/square/javapoet

https://github.com/square/kotlinpoet

https://github.com/Jintin/ComposeAdapter

https://github.com/Jintin/AutoFactory
Q&A

More Related Content

PPTX
Annotation processing
ODP
To inject or not to inject: CDI is the question
PDF
Annotation Processing in Android
ODP
What's new in Java EE 6
PDF
How Does Kubernetes Build OpenAPI Specifications?
PDF
Dependency Injection with CDI in 15 minutes
PDF
On Processors, Compilers and @Configurations
PDF
CDI: How do I ?
Annotation processing
To inject or not to inject: CDI is the question
Annotation Processing in Android
What's new in Java EE 6
How Does Kubernetes Build OpenAPI Specifications?
Dependency Injection with CDI in 15 minutes
On Processors, Compilers and @Configurations
CDI: How do I ?

What's hot (20)

PDF
Are app servers still fascinating
PPTX
When Enterprise Java Micro Profile meets Angular
PPTX
Jdk 7 4-forkjoin
PPT
Python Evolution
PPTX
Code generation for alternative languages
PDF
Overview of Android Infrastructure
PPTX
Explanation onAttach() of Fragment class in Android
PPTX
Introduction to CDI and DI in Java EE 6
PDF
50 new features of Java EE 7 in 50 minutes
PPTX
Getting started with Java 9 modules
PPTX
Making Java more dynamic: runtime code generation for the JVM
PDF
Why Spring <3 Kotlin
PPT
ExtJs Basic Part-1
PDF
Concurrency and Thread-Safe Data Processing in Background Tasks
PDF
Con-FESS 2015 - Having Fun With Javassist
PDF
Java Enterprise Edition
PPTX
PDF
Developing Useful APIs
PPTX
Developing components and extensions for ext js
PPTX
Enterprise js pratices
Are app servers still fascinating
When Enterprise Java Micro Profile meets Angular
Jdk 7 4-forkjoin
Python Evolution
Code generation for alternative languages
Overview of Android Infrastructure
Explanation onAttach() of Fragment class in Android
Introduction to CDI and DI in Java EE 6
50 new features of Java EE 7 in 50 minutes
Getting started with Java 9 modules
Making Java more dynamic: runtime code generation for the JVM
Why Spring <3 Kotlin
ExtJs Basic Part-1
Concurrency and Thread-Safe Data Processing in Background Tasks
Con-FESS 2015 - Having Fun With Javassist
Java Enterprise Edition
Developing Useful APIs
Developing components and extensions for ext js
Enterprise js pratices
Ad

Similar to Annotation Processing (20)

PDF
Workshop 23: ReactJS, React & Redux testing
PDF
TypeScript for Java Developers
PPTX
Back-2-Basics: .NET Coding Standards For The Real World (2011)
PDF
Testable JavaScript: Application Architecture
PDF
Stencil the time for vanilla web components has arrived
PDF
Daggerate your code - Write your own annotation processor
PDF
The Naked Bundle - Tryout
PDF
Introduction to Griffon
ODP
Bring the fun back to java
PDF
The Naked Bundle - Symfony Live London 2014
PDF
Whoops! where did my architecture go?
PPT
Testing of javacript
PDF
Stencil: The Time for Vanilla Web Components has Arrived
PPTX
C# 6.0 Preview
PDF
Angular 2 for Java Developers
PDF
Jollen's Presentation: Introducing Android low-level
PDF
How React Native, Appium and me made each other shine @Frontmania 16-11-2018
PPT
Google Web Toolkits
PPTX
Protractor framework architecture with example
PDF
Commenting in Agile Development
Workshop 23: ReactJS, React & Redux testing
TypeScript for Java Developers
Back-2-Basics: .NET Coding Standards For The Real World (2011)
Testable JavaScript: Application Architecture
Stencil the time for vanilla web components has arrived
Daggerate your code - Write your own annotation processor
The Naked Bundle - Tryout
Introduction to Griffon
Bring the fun back to java
The Naked Bundle - Symfony Live London 2014
Whoops! where did my architecture go?
Testing of javacript
Stencil: The Time for Vanilla Web Components has Arrived
C# 6.0 Preview
Angular 2 for Java Developers
Jollen's Presentation: Introducing Android low-level
How React Native, Appium and me made each other shine @Frontmania 16-11-2018
Google Web Toolkits
Protractor framework architecture with example
Commenting in Agile Development
Ad

More from Jintin Lin (17)

PDF
KSP intro
PDF
我的開源之旅
PDF
Dagger 2 vs koin
PDF
ButterKnife
PDF
數學系的資訊人生
PDF
Instant app Intro
PDF
KVO implementation
PDF
iOS NotificationCenter intro
PDF
App design guide
PDF
J霧霾
PDF
transai
PDF
Swimat - Swift formatter
PDF
Swift Tutorial 2
PDF
Swift Tutorial 1
PDF
Andle
PDF
Realism vs Flat design
PDF
Android Service Intro
KSP intro
我的開源之旅
Dagger 2 vs koin
ButterKnife
數學系的資訊人生
Instant app Intro
KVO implementation
iOS NotificationCenter intro
App design guide
J霧霾
transai
Swimat - Swift formatter
Swift Tutorial 2
Swift Tutorial 1
Andle
Realism vs Flat design
Android Service Intro

Recently uploaded (20)

PPTX
Foundation to blockchain - A guide to Blockchain Tech
PPTX
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
PPTX
Current and future trends in Computer Vision.pptx
PPTX
Safety Seminar civil to be ensured for safe working.
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PPTX
Geodesy 1.pptx...............................................
PDF
Operating System & Kernel Study Guide-1 - converted.pdf
PDF
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
PDF
R24 SURVEYING LAB MANUAL for civil enggi
PPTX
OOP with Java - Java Introduction (Basics)
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPT
Mechanical Engineering MATERIALS Selection
PPTX
Construction Project Organization Group 2.pptx
PDF
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
PPTX
UNIT-1 - COAL BASED THERMAL POWER PLANTS
PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PDF
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
PDF
PREDICTION OF DIABETES FROM ELECTRONIC HEALTH RECORDS
PDF
composite construction of structures.pdf
PDF
SM_6th-Sem__Cse_Internet-of-Things.pdf IOT
Foundation to blockchain - A guide to Blockchain Tech
MET 305 2019 SCHEME MODULE 2 COMPLETE.pptx
Current and future trends in Computer Vision.pptx
Safety Seminar civil to be ensured for safe working.
CYBER-CRIMES AND SECURITY A guide to understanding
Geodesy 1.pptx...............................................
Operating System & Kernel Study Guide-1 - converted.pdf
Mohammad Mahdi Farshadian CV - Prospective PhD Student 2026
R24 SURVEYING LAB MANUAL for civil enggi
OOP with Java - Java Introduction (Basics)
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
Mechanical Engineering MATERIALS Selection
Construction Project Organization Group 2.pptx
Evaluating the Democratization of the Turkish Armed Forces from a Normative P...
UNIT-1 - COAL BASED THERMAL POWER PLANTS
Embodied AI: Ushering in the Next Era of Intelligent Systems
The CXO Playbook 2025 – Future-Ready Strategies for C-Suite Leaders Cerebrai...
PREDICTION OF DIABETES FROM ELECTRONIC HEALTH RECORDS
composite construction of structures.pdf
SM_6th-Sem__Cse_Internet-of-Things.pdf IOT

Annotation Processing

  • 2. About me Tim / Jintin Android / iOS developer Senior Software Engineer 
 @ Carousell https://github.com/Jintin https://medium.com/@Jintin
  • 9. “Annotation Processing is a tool we can use to help us generate code in compile time by labeling Annotations inside our source code.”
  • 10. Pros & Cons + Less boilerplate code + No Runtime Error - Block incremental build - Kotlin 1.3.30+ - Gradle 4.7+ - Compile overhead
  • 14. How we use it dependencies { implementation 'com.google.dagger:dagger:2.x' kapt ‘com.google.dagger:dagger-compiler:2.x' } kapt stands for Kotlin annotation processing tool
  • 15. Module structure Library module (optional) Processor(compiler) module Annotation module
  • 18. Attribute @GET(“XXX_Value") Observable getAPI(); @Component(modules = { AModule.class, BModule.class, CModule.class}) public interface MyComponent {}
  • 19. Attribute @Target(METHOD) @Retention(RUNTIME) public @interface GET { String value() default ""; } @Retention(RUNTIME) @Target(TYPE) public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; }
  • 20. Attribute Primitive types (int, long, etc.) String Classes (Foo::class) Enums Other annotations Arrays of the types listed above.
  • 24. Retention @Target(ElementType.METHOD) @Retention(SOURCE) public @interface Override {} @Target({ METHOD, CONSTRUCTOR, FIELD }) @Retention(RUNTIME) public @interface Inject {}
  • 25. Retention public enum RetentionPolicy { /* only exist before compile finish. */ SOURCE, /* recorded in the class file by the compiler but need not be retained by the VM at run time. */ CLASS, /* to be recorded in the class file and can be used at run time, so they may be read reflectively. */ RUNTIME }
  • 26. Retention public enum RetentionPolicy { /* only exist before compile finish. */ SOURCE, /* recorded in the class file by the compiler but need not be retained by the VM at run time. */ CLASS, /* to be recorded in the class file and can be used at run time, so they may be read reflectively. */ RUNTIME }
  • 27. Retention public enum RetentionPolicy { /* only exist before compile finish. */ SOURCE, /* recorded in the class file by the compiler but need not be retained by the VM at run time. */ CLASS, /* to be recorded in the class file and can be used at run time, so they may be read reflectively. */ RUNTIME }
  • 28. Retention public enum RetentionPolicy { /* only exist before compile finish. */ SOURCE, /* recorded in the class file by the compiler but need not be retained by the VM at run time. */ CLASS, /* to be recorded in the class file and can be used at run time, so they may be read reflectively. */ RUNTIME }
  • 29. Processor module Only used in compile phase. Not include in final Jar/Apk. Can contain several Processors.
  • 30. Hook
  • 31. AutoService Hook @AutoService(Processor::class) class AdapterProcessor : Processor() 
 dependencies { implementation ‘com.google.auto.service:auto-service:1.X’ }
  • 32. public interface Processor { /** Initializes with the processing environment. */ void init(ProcessingEnvironment processingEnv); /** Returns the target the annotation types to process. */ Set<String> getSupportedAnnotationTypes(); /** Processes a set of annotation on type elements. */ boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv); … } Processor
  • 33. public interface Processor { /** Initializes with the processing environment. */ void init(ProcessingEnvironment processingEnv); /** Returns the target the annotation types to process. */ Set<String> getSupportedAnnotationTypes(); /** Processes a set of annotation on type elements. */ boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv); … } Processor
  • 34. public interface Processor { /** Initializes with the processing environment. */ void init(ProcessingEnvironment processingEnv); /** Returns the target the annotation types to process. */ Set<String> getSupportedAnnotationTypes(); /** Processes a set of annotation on type elements. */ boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv); … } Processor
  • 35. public interface Processor { /** Initializes with the processing environment. */ void init(ProcessingEnvironment processingEnv); /** Returns the target the annotation types to process. */ Set<String> getSupportedAnnotationTypes(); /** Processes a set of annotation on type elements. */ boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv); … } Processor
  • 36. Element Unit of code element. - PackageElement: Package - TypeElement: Class, Interface - ExecutableElement: Method, Constructor
  • 37. @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { if (element.getKind() != ElementKind.INTERFACE) { error("Only interface can be used with MyAnnotation", element); return true; } TypeElement typeElement = (TypeElement) element; typeElement.getInterfaces(); typeElement.getSuperclass(); typeElement.getSimpleName(); MyAnnotation anno = element.getAnnotation(MyAnnotation.class); /** Custom logic to build the relation graph and generate the file*/ } return true; }
  • 38. @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { if (element.getKind() != ElementKind.INTERFACE) { error("Only interface can be used with MyAnnotation", element); return true; } TypeElement typeElement = (TypeElement) element; typeElement.getInterfaces(); typeElement.getSuperclass(); typeElement.getSimpleName(); MyAnnotation anno = element.getAnnotation(MyAnnotation.class); /** Custom logic to build the relation graph and generate the file*/ } return true; }
  • 39. @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { if (element.getKind() != ElementKind.INTERFACE) { error("Only interface can be used with MyAnnotation", element); return true; } TypeElement typeElement = (TypeElement) element; typeElement.getInterfaces(); typeElement.getSuperclass(); typeElement.getSimpleName(); MyAnnotation anno = element.getAnnotation(MyAnnotation.class); /** Custom logic to build the relation graph and generate the file*/ } return true; }
  • 40. @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { if (element.getKind() != ElementKind.INTERFACE) { error("Only interface can be used with MyAnnotation", element); return true; } TypeElement typeElement = (TypeElement) element; typeElement.getInterfaces(); typeElement.getSuperclass(); typeElement.getSimpleName(); MyAnnotation anno = element.getAnnotation(MyAnnotation.class); /** Custom logic to build the relation graph and generate the file*/ } return true; }
  • 41. @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) { if (element.getKind() != ElementKind.INTERFACE) { error("Only interface can be used with MyAnnotation", element); return true; } TypeElement typeElement = (TypeElement) element; typeElement.getInterfaces(); typeElement.getSuperclass(); typeElement.getSimpleName(); MyAnnotation anno = element.getAnnotation(MyAnnotation.class); /** Custom logic to build the relation graph and generate the file*/ } return true; }
  • 42. How to create file?
  • 44. Filer @Override public synchronized void init(ProcessingEnvironment env) { super.init(env); filer = env.getFiler(); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnv) { … filer.createSourceFile(“NewFile", element); }
  • 45. How to create code?
  • 46. JavaPoet/KotlinPoet Provide simple API to generate Java/Kotlin file Both Square open source projects Over 8000 stars in total
  • 47. MethodSpec main = MethodSpec.methodBuilder("main") .build(); JavaPoet
  • 48. MethodSpec main = MethodSpec.methodBuilder("main") .build();
 
 void main() { } JavaPoet
  • 49. MethodSpec main = MethodSpec.methodBuilder("main") .addParameter(String[].class, "args") .build();
 
 void main(String[] args) { } JavaPoet
  • 50. MethodSpec main = MethodSpec.methodBuilder("main") .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!") .build();
 
 void main(String[] args) { System.out.println("Hello, JavaPoet!"); } JavaPoet
  • 51. MethodSpec main = MethodSpec.methodBuilder("main") .addParameter(String[].class, "args") .addStatement("$T.out.println($S)", System.class, “Hello, JavaPoet!")
 .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .build();
 
 public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } JavaPoet
  • 52. TypeSpec helloWorld = TypeSpec.classBuilder("HellowWorld") .addMethod(MethodSpec.{…}) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .build(); public final class HelloWorld { public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet
  • 53. Tips Find the boilerplate of daily work, eg: findViewById, dependency graph, deep link, etc. Find the pattern and define each component. Label each component with annotation. Create processor to generate code and link each component.
  • 55. Factory public interface Animal {} public class Cat implements Animal {} public class Dog implements Animal {} public final class AnimalFactory { public static Animal createAnimal(String type) { switch(type) { case "cat": return new Cat(); case "dog": return new Dog(); } throw new RuntimeException("not support type"); } }
  • 56. Factory public interface Animal {} public class Cat implements Animal {} public class Dog implements Animal {} public final class AnimalFactory { public static Animal createAnimal(String type) { switch(type) { case "cat": return new Cat(); case "dog": return new Dog(); } throw new RuntimeException("not support type"); } }
  • 57. Auto Generate? @AutoFactory public interface Animal {} 
 @AutoElement(AnimalTags.CAT) public class Cat implements Animal {} @AutoElement(AnimalTags.DOG) public class Dog implements Animal {} // https://github.com/Jintin/AutoFactory
  • 59. 1 ViewHolder public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } }
  • 60. Add ViewHolder public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; protected static final int TYPE_HOLDER2 = 2; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } case TYPE_HOLDER2: { return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } }
  • 61. Add more ViewHolder public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; protected static final int TYPE_HOLDER2 = 2; protected static final int TYPE_HOLDER3 = 3; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } case TYPE_HOLDER2: { return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false)); } case TYPE_HOLDER3: { return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } }
  • 62. Even more ViewHolders public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; protected static final int TYPE_HOLDER2 = 2; protected static final int TYPE_HOLDER3 = 3; protected static final int TYPE_HOLDER4 = 4; protected static final int TYPE_HOLDER5 = 5; protected static final int TYPE_HOLDER6 = 6; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } case TYPE_HOLDER2: { return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false)); } case TYPE_HOLDER3: { return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false)); } case TYPE_HOLDER4: { return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false)); } case TYPE_HOLDER5: { return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false)); } case TYPE_HOLDER6: { return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } }
  • 63. Even more Adapters public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; protected static final int TYPE_HOLDER2 = 2; protected static final int TYPE_HOLDER3 = 3; protected static final int TYPE_HOLDER4 = 4; protected static final int TYPE_HOLDER5 = 5; protected static final int TYPE_HOLDER6 = 6; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } case TYPE_HOLDER2: { return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false)); } case TYPE_HOLDER3: { return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false)); } case TYPE_HOLDER4: { return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false)); } case TYPE_HOLDER5: { return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false)); } case TYPE_HOLDER6: { return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } } public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected static final int TYPE_HOLDER1 = 1; protected static final int TYPE_HOLDER2 = 2; protected static final int TYPE_HOLDER3 = 3; protected static final int TYPE_HOLDER4 = 4; protected static final int TYPE_HOLDER5 = 5; protected static final int TYPE_HOLDER6 = 6; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HOLDER1: { return new Holder1(LayoutInflater.from(context).inflate(R.layout.view1, parent, false)); } case TYPE_HOLDER2: { return new Holder2(LayoutInflater.from(context).inflate(R.layout.view2, parent, false)); } case TYPE_HOLDER3: { return new Holder3(LayoutInflater.from(context).inflate(R.layout.view3, parent, false)); } case TYPE_HOLDER4: { return new Holder4(LayoutInflater.from(context).inflate(R.layout.view4, parent, false)); } case TYPE_HOLDER5: { return new Holder5(LayoutInflater.from(context).inflate(R.layout.view5, parent, false)); } case TYPE_HOLDER6: { return new Holder6(LayoutInflater.from(context).inflate(R.layout.view6, parent, false)); } default: throw new RuntimeException("Not support type" + viewType); } } }
  • 64. Annotation Processing @BindHolder(Holder1.class) @BindHolder(Holder2.class) @BindHolder(Holder3.class, R.layout.view3) @BindHolder(Holder4.class, R.layout.view4) public class MyAdapter extends MyAdapterHelper {} @BindLayout(R.layout.item_holder1) class ViewHolder1 extends RecyclerView.ViewHolder {} @BindLayout(R.layout.item_holder2) class ViewHolder2 extends RecyclerView.ViewHolder {} // https://github.com/Jintin/ComposeAdapter
  • 67. Q&A