SlideShare a Scribd company logo
How to code
to code less
github.com/anton-novikau
Anton Novikau
Lead Android Developer @ Viber Media
Boilerplate Fighters!
Agenda
What is Annotation Processor?
How does it work?
Project structure
Create Annotation Processor
How to debug Processor’s code?
Demo time!
How to setup a goal?
Java Annotation Processors
Processing Rounds
TODO BUILD DONE
D
A C
B
E
F
Round 1
Processing Rounds
TODO BUILD DONE
Round 1
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 1
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 1
AA
FA
FB D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 1
AA
FA
FB
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 2
AA
FA
FB
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 2
AA
FA
FB
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 2
AA
FA
FB
AAA
D
A C
B
E
F
Processing Rounds
TODO BUILD DONE
Round 2
AAA
D
A C
B
E
F
AA
FA
FB
Processing Rounds
TODO BUILD DONE
Round 3
AAA
D
A C
B
E
F
AA
FA
FB
Processing Rounds
TODO BUILD DONE
Round 3
AAA
D
A C
B
E
F
AA
FA
FB
public class Person {
private String firstName;
private String lastName;
private Date birthday;
}
@Pojo
@Pojo
public class Person {
private String firstName;
private String lastName;
private Date birthday;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Date getBirthday() {
return birthday;
}
Where to get source data to generate code?
Before we start
Inheritance vs Composition
What should be a start point for our processor?
Inheritance
public class Contact implements Parcelable {
}
public static final Creator<Contact> CREATOR =
new Creator<Contact>() {
@Override
public Contact createFromParcel(Parcel source) {
return new Contact(source);
}
@Override
public Contact[] newArray(int size) {
return new Contact[size];
}
};
...
Inheritance
public class Contact implements Parcelable {
}
public class Contact implements Parcelable {
}
Inheritance
...
public Contact() {
}
Contact(Parcel source) {
...
}
...
public class Contact implements Parcelable {
}
Inheritance
...
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
...
}
class Smart_Contact extends Contact {
// creator
// constructor
// methods from Parcelable
}
@SmartParcelable
public abstract class Contact implements Parcelable {
}
Inheritance
class Smart_Contact extends Contact {
// creator
// constructor
// methods from Parcelable
}
@SmartParcelable
public abstract class Contact implements Parcelable {
public static Contact create() {
return new Smart_Contact();
}
}
Inheritance
Composition
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
...
public void onMigrateImageClicked(View v) {
MainActivityPermissionsDispatcher
.migrateImageWithPermissionCheck(this);
}
@NeedsPermission(WRITE_EXTERNAL_STORAGE)
void migrateImage() {
...
}
}
Composition
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
...
public void onMigrateImageClicked(View v) {
MainActivityPermissionsDispatcher
.migrateImageWithPermissionCheck(this);
}
@NeedsPermission(WRITE_EXTERNAL_STORAGE)
void migrateImage() {
...
}
}
Composition
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
...
public void onMigrateImageClicked(View v) {
MainActivityPermissionsDispatcher
.migrateImageWithPermissionCheck(this);
}
@NeedsPermission(WRITE_EXTERNAL_STORAGE)
void migrateImage() {
...
}
}
Where to get source data to generate code?
What should be a start point for our processor?
Before we start
Inheritance vs Composition
Effort of using your generated code vs creating a boilerplate code
Cursor boilerplate
public class ContactEntity {
long id;
String name;
Uri photoUri;
}
Cursor boilerplate
ContactEntity contact = new ContactEntity();
contact.setId(c.getLong(0));
contact.setName(c.getString(1));
contact.setPhotoUri(Uri.parse(c.getString(2)));
Cursor c = db.query("contacts",
"_ID = ?",
new String[] {"_ID", "NAME", "PHOTO"},
new String[] { String.valueOf(id) },
null, null, null);
ContactEntity contact = new ContactEntity();
contact.setId(c.getLong(0));
contact.setName(c.getString(1));
String uri = c.getString(2);
if (uri != null) {
contact.setPhotoUri(Uri.parse(uri));
}
Cursor boilerplate
Cursor c = db.query("contacts",
"_ID = ?",
new String[] {"_ID", "NAME", "PHOTO"},
new String[] { String.valueOf(id) },
null, null, null);
Cursor boilerplate
ContentValues values = new ContentValues();
values.put("_ID", contact.getId());
values.put("NAME", contact.getName());
values.put("PHOTO", contact.getPhotoUri().toString());
db.update("contacts",
values,
"_ID = ?",
new String[] { String.valueOf(contact.getId()) });
ContentValues values = new ContentValues();
values.put("_ID", contact.getId());
values.put("NAME", contact.getName());
String photoUri = contact.getPhotoUri() != null
? contact.getPhotoUri().toString()
: null
values.put("PHOTO", photoUri);
Cursor boilerplate
db.update("contacts",
values,
"_ID = ?",
new String[] { String.valueOf(contact.getId()) });
Goal
public class ContactEntity {
long id;
String name;
Uri photoUri;
}
Goal
@Entity(table = "contacts")
public class ContactEntity {
@Column(name = "_ID")
@PrimaryKey
long id;
@Column(name = "NAME")
String name;
@Column(name = "PHOTO", adapter = UriTypeAdapter.class)
Uri photoUri;
}
Project Structure
Project
api
processors
application
API Module
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
compileOnly 'com.google.android:android:4.1.1.4'
}
API Module
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
compileOnly 'com.google.android:android:4.1.1.4'
}
API Module
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Entity {
String table();
}
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface Column {
String name();
Class<? extends TypeAdapter<?>> adapter();
}
API Module
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface Entity {
String table();
}
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface Column {
String name();
Class<? extends TypeAdapter<?>> adapter();
}
Processors Module
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
implementation project(':api')
}
Processors Module
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
implementation project(':api')
}
Create Annotation Processor
@SupportedAnnotationTypes("roomie.api.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityHelperProcessor extends AbstractProcessor {
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
...
}
@Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
...
}
}
Create Annotation Processor
@SupportedAnnotationTypes("roomie.api.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityHelperProcessor extends AbstractProcessor {
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
...
}
@Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
...
}
}
Create Annotation Processor
@SupportedAnnotationTypes("roomie.api.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityHelperProcessor extends AbstractProcessor {
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
...
}
@Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
...
}
}
Create Annotation Processor
@SupportedAnnotationTypes("roomie.api.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityHelperProcessor extends AbstractProcessor {
@Override
public void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
...
}
@Override
public boolean process(
Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
...
}
}
Register Processor
Project
processors
src
main
resources
META-INF
services
Old Fashioned way
javax.annotation.processing.Processor
roomie.codegen.EntityHelperProcessor
...
Register Processor
Modern way
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
implementation project(':api')
implementation 'com.google.auto:auto-common:0.8'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
}
Register Processor
Modern way
@AutoService(Processor.class)
@SupportedAnnotationTypes("roomie.api.Entity")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityHelperProcessor extends AbstractProcessor {
...
}
Write a simple Class
package roomie.example;
public class DemoImpl extends Demo {
int counter;
public void print(String msg) {
System.out.println(msg);
}
}
Write a simple Class: raw text
JavaFileObject sourceFile =
filer.createSourceFile(qualifiedName, annotatedClass);
try (Writer writer = sourceFile.openWriter()) {
writer.append("package ");
writer.append(packageName).append(";nn");
writer.append("public class ").append(className);
writer.append(" extends ");
writer.append(annotatedClass.simpleName()).append(" {n");
writer.append(" int counter;nn");
writer.append(" public void print(String msg) {n");
writer.append(" System.out.println(msg);n");
writer.append(" }n");
writer.append("}n");
writer.flush();
}
Processors Module
apply plugin: 'java-library'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
implementation project(':api')
implementation 'com.squareup:javapoet:1.9.0'
implementation 'com.google.auto:auto-common:0.8'
compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
}
JavaFile DemoImpl.java
TypeSpec class DemoImpl
MethodSpec void print()
FieldSpec int counter
ParameterSpec String msg
JavaPoet Java
=
Write a simple Class: JavaPoet
Define Class
TypeSpec.Builder classContent =
TypeSpec.classBuilder(className)
.addModifiers(Modifier.PUBLIC)
.superclass(annotatedClass);
Write a simple Class: JavaPoet
Define Method and Field
MethodSpec print =
MethodSpec.methodBuilder("print")
.addModifiers(Modifier.PUBLIC)
.addParameter(String.class, "msg")
.addStatement(“$L.out.println(msg)",
System.class)
.build();
FieldSpec counter =
FieldSpec.builder(int.class, "counter").build();
classContent.addMethod(print);
classContent.addField(counter);
Write a simple Class: JavaPoet
Write our Class to a File
JavaFile javaFile = JavaFile.builder(packageName,
classContent.build())
.indent(" ")
.build();
JavaFileObject sourceFile = filer.createSourceFile(
qualifiedName,
annotatedClass);
try (Writer writer = sourceFile.openWriter()) {
writer.write(javaFile.toString());
}
Don’t worry.
We’ve almost finished
Application Module
apply plugin: 'com.android.application'
android {
...
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
dependencies {
implementation project(':api')
annotationProcessor project(':codegen')
...
}
Application Module
apply plugin: 'com.android.application'
android {
...
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
dependencies {
implementation project(':api')
annotationProcessor project(':codegen')
...
}
Application Module
apply plugin: 'com.android.application'
android {
...
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
dependencies {
implementation project(':api')
annotationProcessor project(':codegen')
...
}
How to Debug?
How to Debug?
Setup Gradle Daemon
vim ~/.gradle/gradle.properties
org.gradle.daemon=true
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,
server=y,suspend=n,address=5005
Start Daemon and Connect
./gradlew --stop
./gradlew --daemon
./gradlew clean :sample:compileDebugJavaWithJavac
Demo Time
Conclusion
Thank you!
Questions?
Useful Links
Hannes Dorfmann - Annotation Processing 101
Eugenio Marletti - Pushing the limits of Kotlin annotation processing
Demo App (aka Roomie) Source Code

More Related Content

What's hot (20)

PDF
Testable Android Apps DroidCon Italy 2015
Fabio Collini
 
PDF
Introduction to cdi given at java one 2014
Antoine Sabot-Durand
 
PDF
Android Wear CodeLab - GDG Firenze
Fabio Collini
 
PDF
JUnit 5 — New Opportunities for Testing on the JVM
VMware Tanzu
 
PDF
Using hilt in a modularized project
Fabio Collini
 
PDF
Level Up Your Android Build -Droidcon Berlin 2015
Friedger Müffke
 
PDF
Testable Android Apps using data binding and MVVM
Fabio Collini
 
PDF
Enter the gradle
Parameswari Ettiappan
 
PDF
JUnit 5 - Evolution and Innovation - SpringOne Platform 2019
Sam Brannen
 
DOC
Mock test rad 2
ram007inter
 
PDF
Building maintainable app #droidconzg
Kristijan Jurković
 
PDF
Pavlo Zhdanov "Java and Swift: How to Create Applications for Automotive Head...
LogeekNightUkraine
 
PPTX
Angular 5 presentation for beginners
Imran Qasim
 
PPTX
Angular interview questions
Goa App
 
PPTX
JUnit 5: What's New and What's Coming - Spring I/O 2019
Sam Brannen
 
PPTX
Java Graphics Programming
Riccardo Cardin
 
PPT
Call
razelventura
 
PPT
Angular Introduction By Surekha Gadkari
Surekha Gadkari
 
PDF
JUnit 5 - New Opportunities for Testing on the JVM
Sam Brannen
 
PPT
Rich GUI Testing: Swing and JavaFX
Alex Ruiz
 
Testable Android Apps DroidCon Italy 2015
Fabio Collini
 
Introduction to cdi given at java one 2014
Antoine Sabot-Durand
 
Android Wear CodeLab - GDG Firenze
Fabio Collini
 
JUnit 5 — New Opportunities for Testing on the JVM
VMware Tanzu
 
Using hilt in a modularized project
Fabio Collini
 
Level Up Your Android Build -Droidcon Berlin 2015
Friedger Müffke
 
Testable Android Apps using data binding and MVVM
Fabio Collini
 
Enter the gradle
Parameswari Ettiappan
 
JUnit 5 - Evolution and Innovation - SpringOne Platform 2019
Sam Brannen
 
Mock test rad 2
ram007inter
 
Building maintainable app #droidconzg
Kristijan Jurković
 
Pavlo Zhdanov "Java and Swift: How to Create Applications for Automotive Head...
LogeekNightUkraine
 
Angular 5 presentation for beginners
Imran Qasim
 
Angular interview questions
Goa App
 
JUnit 5: What's New and What's Coming - Spring I/O 2019
Sam Brannen
 
Java Graphics Programming
Riccardo Cardin
 
Angular Introduction By Surekha Gadkari
Surekha Gadkari
 
JUnit 5 - New Opportunities for Testing on the JVM
Sam Brannen
 
Rich GUI Testing: Swing and JavaFX
Alex Ruiz
 

Similar to How to code to code less (20)

PDF
Annotation Processing
Jintin Lin
 
PDF
Infinum Android Talks #02 - How to write an annotation processor in Android
Infinum
 
PDF
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Java User Group Latvia
 
PDF
Adapting clean architecture in android apps
Matso Abgaryan
 
PDF
My way to clean android (EN) - Android day salamanca edition
Christian Panadero
 
PDF
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
DroidConTLV
 
PDF
Write code that writes code!
Jason Feinstein
 
PDF
Intro to Dependency Injection - Or bar
DroidConTLV
 
PDF
Developing Useful APIs
Dmitry Buzdin
 
PDF
Beautiful code
Peter Hilton
 
PPTX
Solid principles
Sahil Kumar
 
PDF
Ow2 Utilities - The Swiss Army Knife Of Ow2 Projects
Guillaume Sauthier
 
PDF
Alexey Buzdin "Maslow's Pyramid of Android Testing"
IT Event
 
PDF
Design patterns in the 21st Century
Samir Talwar
 
PDF
Java Annotation Processing: A Beginner Walkthrough
Mahfuz Islam Bhuiyan
 
PDF
Droidcon Paris 2015
Renaud Boulard
 
PDF
Five android architecture
Tomislav Homan
 
PDF
Enabling White-Box Reuse in a Pure Composition Language
elliando dias
 
PPTX
The Best Way to Become an Android Developer Expert with Android Jetpack
Ahmad Arif Faizin
 
PDF
Better Software: introduction to good code
Giordano Scalzo
 
Annotation Processing
Jintin Lin
 
Infinum Android Talks #02 - How to write an annotation processor in Android
Infinum
 
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Java User Group Latvia
 
Adapting clean architecture in android apps
Matso Abgaryan
 
My way to clean android (EN) - Android day salamanca edition
Christian Panadero
 
Write code that writes code! A beginner's guide to Annotation Processing - Ja...
DroidConTLV
 
Write code that writes code!
Jason Feinstein
 
Intro to Dependency Injection - Or bar
DroidConTLV
 
Developing Useful APIs
Dmitry Buzdin
 
Beautiful code
Peter Hilton
 
Solid principles
Sahil Kumar
 
Ow2 Utilities - The Swiss Army Knife Of Ow2 Projects
Guillaume Sauthier
 
Alexey Buzdin "Maslow's Pyramid of Android Testing"
IT Event
 
Design patterns in the 21st Century
Samir Talwar
 
Java Annotation Processing: A Beginner Walkthrough
Mahfuz Islam Bhuiyan
 
Droidcon Paris 2015
Renaud Boulard
 
Five android architecture
Tomislav Homan
 
Enabling White-Box Reuse in a Pure Composition Language
elliando dias
 
The Best Way to Become an Android Developer Expert with Android Jetpack
Ahmad Arif Faizin
 
Better Software: introduction to good code
Giordano Scalzo
 
Ad

Recently uploaded (20)

PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
PDF
Biography of Daniel Podor.pdf
Daniel Podor
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
Building Real-Time Digital Twins with IBM Maximo & ArcGIS Indoors
Safe Software
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
Transcript: New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Fl Studio 24.2.2 Build 4597 Crack for Windows Free Download 2025
faizk77g
 
Biography of Daniel Podor.pdf
Daniel Podor
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
Ad

How to code to code less