Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
How can we write less code by generating code?
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Gil Goldzweig
April 24, 2018
Programming
58
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
How can we write less code by generating code?
Gil Goldzweig
April 24, 2018
More Decks by Gil Goldzweig
See All by Gil Goldzweig
Reactive UI in Android (Jetpack compose)
gilgoldzweig
0
400
Kotlin-Workshop Day #3
gilgoldzweig
0
26
Kotlin Workshop day #2
gilgoldzweig
0
190
Kotlin-Workshop Day #1
gilgoldzweig
0
33
Google IO recap
gilgoldzweig
0
40
Other Decks in Programming
See All in Programming
作って学ぶSpring BootのAuto Configuration / JJUG Night Seminar 2026-10-19
rshindo
0
140
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
270
當我們開始不讀 Code - AI Agent 時代,Code Review 與 Clean Code 還剩下什麼?
jame2408
1
190
すこし踏み込む CancellationToken
htkym
2
1.7k
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
420
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
180
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
1.1k
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
phperだってパンチカードでコーディングしたい
o0h
PRO
0
330
カツオ、ご期待ください
suneo3476
0
190
Agents on Rails - Rails at Scale 2026
irinanazarova
0
560
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
1.9k
Featured
See All Featured
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
We Have a Design System, Now What?
morganepeng
55
8.4k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
270
How STYLIGHT went responsive
nonsquared
100
6.3k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
950
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
300
Scaling GitHub
holman
464
140k
Agile that works and the tools we love
rasmusluckow
331
22k
How to Ace a Technical Interview
jacobian
280
24k
The Language of Interfaces
destraynor
162
27k
Transcript
How can we write less code by generating code? (Not
skynet) 24/4/2018
Gil Goldzweig https://github.com/gilgoldzweig Android developer @ NYX
None
How can we write less code by generating code? 10/01/2019
Annotation Processing
Annotation Processor tool - APT • A tool for the
Javac(Java compiler) • Added JDK 1.5 • Reads & Process @Annotated sources
Chain of events Write (.java) Compile (.class) Package (.jar) Dex
(.dex) Package (.apk) APT (.java) Project lifecycle - APT
Project lifecycle Write (.java) Compile (.class) Package (.jar)
Chain of events Write (.java) Compile (.class) Package (.jar) Dex
(.dex) Package (.apk) Project lifecycle - android
Example
Before - Gencycler RecyclerView
Before - Gencycler ViewHolder class LectureViewHolder extends RecyclerView.ViewHolder { TextView
title; TextView description; TextView date; LectureViewHolder(View itemView) { super(itemView); title = itemView.findViewById(R.id.lecture_title); description = itemView.findViewById(R.id.lecture_desc); date = itemView.findViewById(R.id.lecture_date); } }
Before - Gencycler Adapter - OnCreateViewHolder public class LectureAdapter extends
RecyclerView.Adapter<LectureViewHolder> { … @Override public LectureViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new LectureViewHolder(inflater .inflate(R.layout.item_lecture, parent, false)); } }
Before - Gencycler Adapter - GetItemCount public class LectureAdapter extends
RecyclerView.Adapter<LectureViewHolder> { … @Override public int getItemCount() { return lectures.size(); } }
Before - Gencycler Adapter - GetItemViewType public class LectureAdapter extends
RecyclerView.Adapter<LectureViewHolder> { … @Override public int getItemViewType(int position) { return super.getItemViewType(position); } }
Before - Gencycler RecyclerView - OnBindViewHolder public class LectureAdapter extends
RecyclerView.Adapter<LectureViewHolder> { … @Override public void onBindViewHolder(LectureViewHolder holder, int position) { Lecture lecture = lectures.get(position); } }
Fun Fact 81
Gencycler
RecyclerView + Gencycler public class LectureAdapter { } Recyclerview -
Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public
class LectureAdapter { } Recyclerview - Gencycler
RecyclerView + Gencycler @RecyclerAdapter public class LectureAdapter { } Recyclerview
- Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class) public class LectureAdapter {
} Recyclerview - Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public
class LectureAdapter { } Recyclerview - Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public
class LectureAdapter { } Recyclerview - Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public
class LectureAdapter extends GeneratedLectureAdapter { } Recyclerview - Gencycler
RecyclerView + Gencycler @RecyclerAdapter(data = Lecture.class, ui = R.layout.item_lecture) public
class LectureAdapter extends GeneratedLectureAdapter { @Override public void onBindLectureViewHolder(LectureViewHolder holder, int position, @NotNull Lecture lecture) { //Actual logic (setText etc… ) } } Recyclerview - Gencycler
7 Lines
81 vs 7 Lines
Questions?
1. Annotations 2. Processor 2.1 Code Generator Components
1. Annotations 2. Processor 2.1 Code Generator Components
Annotation public interface RecyclerAdapter {}
Annotation public @interface RecyclerAdapter {}
Annotation @Target(ElementType.TYPE) public @interface RecyclerAdapter {}
Target - Limit where the annotation can be placed •
Type(Class) • Field • Method • Parameter • AnnotationType • Constructor • Package • LocalVariable (Java 1.8) • TypeParameter (Java 1.8)
Annotation @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface RecyclerAdapter {}
Retention - When will the annotation can be used •
Source(Annotation processor) • Runtime(Reflection) • Class(Annotation processor + Reflection)
Reflection Reflection • Create new instances of objects • Invoke
methods • Examine properties of classes (fields, methods, constructors) • Modify field values
Reflection Reflection
Reflection Reflection - drawbacks • No compile-time verification • Breaks
easily • Expensive • Hard to maintain
Annotation @Retention(RetentionPolicy.SOURCE) //Compile-time @Target(ElementType.TYPE) //Can be placed on a class
public @interface RecyclerAdapter {}
Questions?
1. Annotations 2. Processor 2.1 Code Generator Components
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { @Override public synchronized
void init(ProcessingEnvironment env) { } } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { @Override public synchronized
void init(ProcessingEnvironment env) { } } Processor
AbstractProcessor ProcessingEnvironment • Filer - used to create new source,
class, or auxiliary files • Opptions • Messenger - Reports errors, warnings, and other notices • Utility methods for using elements/types
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
Set<String> getSupportedAnnotationTypes() { return ImmutableSet.of(RecyclerAdapter.class .getCanonicalName()); } } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { } } Processor
None
AbstractProcessor Java sources APT Completed Round one - sources LectureAdapter.java
OtherAdapter.java Processing rounds
AbstractProcessor Java sources APT Completed Round one - sources Processing
rounds LectureAdapter.java OtherAdapter.java Processing rounds
AbstractProcessor public class RecyclerProcessor extends AbstractProcessor { … @Override public
boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) { //RoundEnvironment will hold information about //the LectureAdapter.java & OtherAdapter.Java } } Processor
AbstractProcessor Java sources APT Completed Round one - new source
files generated Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds
AbstractProcessor Processing rounds Java sources APT Completed Round one -
Completed Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds
AbstractProcessor Processing rounds Java sources APT Completed Round two -
generated sources Processing rounds LectureGenrated.java OtherGenrated.java LectureAdapter.java OtherAdapter.java Processing rounds Processing rounds Processing rounds
AbstractProcessor Processing rounds Java sources APT Completed Processing rounds LectureAdapter.java
OtherAdapter.java LectureGenrated.java OtherGenrated.java Round two - generated sources Processing rounds
AbstractProcessor Processing rounds Java sources APT Completed LectureGenrated.java OtherGenrated.java Round
two - Completed Processing rounds LectureAdapter.java OtherAdapter.java Processing rounds
Questions?
1. Annotations 2. Processor 2.1 Code Generator Components
• Automatic ◦ Java/KotlinPoet (open source library created by square)
• Manual ◦ Writer Code generation Code generation
Pros & Cons
+ Easy usage + Very good documentation + Language objects
oriented Automatic - Java/kotlinPoet - Very verbose code
+ Easy usage Manual - StringBuilder - Not language objects
oriented - Hard to maintain properly Manual - Writer
Example
package com.example.helloworld; public final class HelloWorld { public static void
main(String[] args) { System.out.println("Hello, JavaPoet!"); } } What we want to generate
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
JavaPoet - method MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class)
.addParameter(String[].class, "args") .addStatement("System.out.println(\"Hello, JavaPoet!\")") .build();
MethodSpec public static void main(String[] args) { System.out.println("Hello, JavaPoet!"); }
JavaPoet - method / generated
JavaPoet - class TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main)
.build(); JavaPoet - class
JavaPoet - class TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main)
.build(); JavaPoet - method JavaPoet - class
JavaPoet - class TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main)
.build(); JavaPoet - method JavaPoet - class
JavaPoet - class TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(main)
.build(); JavaPoet - class
MethodSpec public final class HelloWorld { public static void main(String[]
args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - class JavaPoet - class JavaPoet - class / generated
JavaPoet - file JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); JavaPoet
- file
package com.example.helloworld; public final class HelloWorld { public static void
main(String[] args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - file / generated
package com.example.helloworld; public final class HelloWorld { public static void
main(String[] args) { System.out.println("Hello, JavaPoet!"); } } JavaPoet - file / generated
JavaPoet - file JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld) .build(); javaFile.writeTo(processingEnv.getFiler());
JavaPoet - file
JavaPoet MethodSpec main = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(void.class) .addParameter(String[].class, "args")
.addStatement("System.out.println(\"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(processingEnv.getFiler()); JavaPoet JavaPoet - code needed
JavaPoet - file Manual Writer codeWriter = procesingEnc.filer .createSource(StandardLocation.SOURCE_OUTPUT) .openWriter();
codeWriter .append("package com.example.helloworld;") .append("\n\n") .append("public final class HelloWorld {\n") .append(" ") .append("public static void main(String[] args) {\n") .append(" ") .append("System.out.println(\"Hello, JavaPoet!\");\n") .append(" }\n") .append("}");
AbstractProcessor • Resources ◦ META_INF ▪ services • javax.annotations.processing.Processor package.name.compiler.RecyclerProcessor
Another processor if exist And another ... Declaring our processor
Benefits • No Runtime performance impact • Write your code
generator once • Trust the generated code Benefits
Thank you
Here are some helpful links to help you build your
own processor :) Annotation Processing : Don’t Repeat Yourself, Generate Your Code. Annotation processing 101 @Eliminate(Boilerplate) JavaPoet KotlinPoet Gencycler