SlideShare a Scribd company logo
1/39
Writing code
that writes code
by
LUONG Hoang Nguyen
Senior Java Technical Lead
ekino.
2/392/39
1. Context
2. Project Lombok
3. Alternatives
4. Conclusion
AGENDA
3/39
1.
Context
4/394/39
Developer job As programmers, we often find ourselves in a similar
position.
We need to achieve the
same functionality, but in different contexts.
We need to repeat information in different
places.
Sometimes we just need to protect ourselves from
carpal tunnel syndrome by
cutting down on repetitive typing
5/395/39
Boiler Plate Code
Syntax Verbosity
Problemsof
theIndustry
Non Standardization
Not following the standard code conventions
Human Error/Dependency
Repeatable things (defining Getters, Setters
etc.)
6/39
2.
Project Lombok
7/39
WHAT IS IT ?
8/398/39
•@Getter / @Setter
•@ToString
•@EqualsAndHashCode
•@Data
•@NoArgsConstructor
•@RequiredArgsConstructor
•@AllArgsConstructor
•@Cleanup
•@Synchronized
•@Slf4j
•@Builder
•val
Features
9/399/39
@Getter / Setter
Features
• Automatic Generation of getters and setters.
• Method will be public unless you explicitly specify an AccessLevel
• @Getter and/or @Setter annotation on class
• Disable getter/setter generation for any field by using the special
AccessLevel.NONE
• @NotNull for nullity check
10/3910/39
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class GetterSetterExample {
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky
is blue.
* @return The current value of this person's age.
Circles are round.
*/
@Getter @Setter private int age = 10;
/**
* Name of the person.
* -- SETTER --
* Changes the name of this person.
*
* @param name The new value.
*/
@Setter(AccessLevel.PROTECTED) private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
}
public class GetterSetterExample {
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky is blue.
* @return The current value of this person's age. Circles are
round.
*/
private int age = 10;
/**
* Name of the person.
* -- SETTER --
* Changes the name of this person.
*
* @param name The new value.
*/
private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
protected void setName(String name) {
this.name = name;
}
}
11/3911/39
@EqualsAndHash
Code
Features
• Generates hashCode and equals implementations from the fields (non-
static, non-transient)
• Parameters 
12/3912/39
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(exclude = { "id", "shape" })
class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
}
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof EqualsAndHashCodeExample)) {
return false;
}
final EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
if (!other.canEqual((Object) this)) {
return false;
}
final Object this$name = this.getName();
final Object other$name = other.getName();
if (this$name == null ? other$name != null : !this$name.equals(other$name)) {
return false;
}
if (Double.compare(this.score, other.score) != 0) {
return false;
}
if (!java.util.Arrays.deepEquals(this.tags, other.tags)) {
return false;
}
return true;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $name = this.getName();
result = result * PRIME + ($name == null ? 0 : $name.hashCode());
final long $score = Double.doubleToLongBits(this.score);
result = result * PRIME + (int) ($score >>> 32 ^ $score);
result = result * PRIME + java.util.Arrays.deepHashCode(this.tags);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof EqualsAndHashCodeExample;
}
}
13/3913/39
@Data
Features
• All together now: A shortcut for @ToString, @EqualsAndHashCode,
@Getter on all fields, @Setter on all non-final fields, and
@RequiredArgsConstructor
• Included annotations with changed parameters can be defined along with
@Data
14/3914/39
import lombok.Data;
@Data
public class DataExample {
private final String name;
private double score;
}
public class DataExample {
private final String name;
private double score;
@java.beans.ConstructorProperties({ "name" })
public DataExample(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public double getScore() {
return this.score;
}
public void setScore(double score) {
this.score = score;
}
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof DataExample)) {
return false;
}
final DataExample other = (DataExample) o;
if (!other.canEqual((Object) this)) {
return false;
}
final Object this$name = this.name;
final Object other$name = other.name;
if (this$name == null ? other$name != null : !this$name.equals(other$name)) {
return false;
}
if (Double.compare(this.score, other.score) != 0) {
return false;
}
return true;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $name = this.name;
result = result * PRIME + ($name == null ? 0 : $name.hashCode());
final long $score = Double.doubleToLongBits(this.score);
result = result * PRIME + (int) ($score >>> 32 ^ $score);
return result;
}
protected boolean canEqual(Object other) {
return other instanceof DataExample;
}
public String toString() {
return "DataExample(name=" + this.name + ", score=" + this.score + ")";
}
}
15/3915/39
@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
Features
• Generates constructors that take no arguments, one argument per final /
non-null field, or one argument for every field.
• Specialized constructor can be made. Compile-time error in case of any
conflicts.
16/3916/39
@Cleanup
Features
• Automatic resource management: Call your close() methods safely with no
hassle.
@Cleanup
InputStream in=new FileInputStream("some/file");
• If the type of object you'd like to cleanup does not have a close() method,
but some other no-argument method like dispose() so write it as
@Cleanup("dispose")
TestClass t = new TestClass();
17/3917/39
@Builder
val
Features
• @Builder generates a static builder() method that returns a builder
instance. This builder instance can be used to build an object of the class
annotated with @Builder (here Person)
• Person.builder().name("Adam Savage").city("San
Francisco").job("Mythbusters").job("Unchained Reaction").build();
• val: You can use val as the type of a local variable declaration instead of
actually writing the type. This feature works on local variables and on
foreach loops only, not on fields
val example = new ArrayList<String>();
example.add("Hello, World!");
18/3918/39
import lombok.Builder;
@Builder
public class BuilderExample {
private String name;
private int age;
}
public class BuilderExample {
private String name;
private int age;
@java.beans.ConstructorProperties({ "name", "age" })
BuilderExample(String name, int age) {
this.name = name;
this.age = age;
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private String name;
private int age;
BuilderExampleBuilder() {
}
public BuilderExample.BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}
public BuilderExample.BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}
public BuilderExample build() {
return new BuilderExample(name, age);
}
public String toString() {
return "BuilderExampleBuilder(name=" + this.name + ", age=" + this.age + ")";
}
}
}
19/3919/39
• Generates Java Boilerplate
• Compile Time Only -> not affect performance for runtime
• For Eclipse and javac
• IntelliJ IDEA & NetBeans too
• Removable with delombok
• Know what is generated
Features
20/3920/39
How does it work? Java compilation has 3 stages:
In the Parse and Enter phase, the compiler parses source files into
an Abstract Syntax Tree (AST
In the Annotation Processing phase, custom annotation processors
are invoked
Annotation processors can do things like validate classes or
generate new resources, including source files.
In the last phase, Analyse and Generate, the compiler generates
class files (byte code) from the Abstract Syntax Trees generated in
phase 1
Project Lombok hooks itself into the compilation process as an
annotation processor. Normally, annotation processors only generate
new source files whereas Lombok modifies existing classes.
21/3921/39
Example • Example we create a very simple Lombok transformation that adds a
helloWorld method to any class annotated as @HelloWorld.
• The basic classes we need to write are:
- Annotation class
- Eclipse handler
- Javac handler (Intellj also supported this)
@HelloWorld
public class MyClass
{
}
public class MyClass {
public void helloWorld() {
System.out.println("Hello
World");
}
}
22/3922/39
Annotation
Example • At first, we just need to create an annotation called HelloWorld that can be
applied to classes.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface HelloWorld {
}
23/3923/39
Handler
Example • Our handler will be adding a new Method Declaration to the Type
Declaration. A Method Declaration is composed of several components.
The AST for our Method Declaration will have this :
24/3924/39
Handler Logic
Example • Our handle method will need to do the following:
1. Mark annotation as processed
2. Create the helloWorld method
3. Inject the helloWorld method into the AST of the annotated class
25/3925/39
Lombok provides our handler with the AST of the annotation node. We know
that the annotation can only be applied to a Type. To get the AST for the Type
(Class), we call annotationNode.up(). The annotation is a child of the Type
AST, so by calling up() we get the parent AST which is the Type AST we need
to modify.
Javac Handler
Example
@ProviderFor(JavacAnnotationHandler.class)
public class HandleHelloWorld implements JavacAnnotationHandler<HelloWorld>{
public boolean handle(AnnotationValues<HelloWorld> annotation, JCAnnotation ast,
JavacNode annotationNode) {
JavacHandlerUtil.markAnnotationAsProcessed(annotationNode, HelloWorld.class);
JavacNode typeNode = annotationNode.up();
if(notAClass(typeNode)) {
annotationNode.addError("@HelloWorld is only supported on a class.");
return false;
}
JCMethodDecl helloWorldMethod = createHelloWorld(typeNode);
JavacHandlerUtil.injectMethod(typeNode, helloWorldMethod);
return true;
}
…
}
26/3926/39
• Start with a method node.
• Add the return type, parameters, access level, throw clause, etc to the
method node.
• Create an expression statement to represent System.out.println("Hello
World")
• Add the expression to the method node.
Javac Handler
Hello world method
Example
private JCMethodDecl createHelloWorld(JavacNode type) {
TreeMaker treeMaker = type.getTreeMaker();
JCModifiers modifiers = treeMaker.Modifiers(Modifier.PUBLIC);
List<JCTypeParameter> methodGenericTypes = List.<JCTypeParameter>nil();
JCExpression methodType = treeMaker.TypeIdent(TypeTag.VOID);
Name methodName = type.toName("helloWorld");
List<JCVariableDecl> methodParameters = List.<JCVariableDecl>nil();
List<JCExpression> methodThrows = List.<JCExpression>nil();
JCExpression printlnMethod =
JavacHandlerUtil.chainDots(treeMaker, type, "System", "out", "println");
List<JCExpression> printlnArgs = List.<JCExpression>of(treeMaker.Literal("hello world"));
JCMethodInvocation printlnInvocation =
treeMaker.Apply(List.<JCExpression>nil(), printlnMethod, printlnArgs);
JCBlock methodBody =
treeMaker.Block(0, List.<JCStatement>of(treeMaker.Exec(printlnInvocation)));
JCExpression defaultValue = null;
return treeMaker.MethodDef(
modifiers,
methodName,
methodType,
methodGenericTypes,
methodParameters,
methodThrows,
methodBody,
defaultValue
);
}
27/3927/39
@UUIDColumn
@JsonColumn
Custom Annotations • We can create custom annotations that helpful for our projects. It will
make standardization for our coding.
@Entity
@Data
public class TestModelEntity {
@Id
@UUIDColumn
private UUID id;
@JsonColumn
private Model model;
….
}
@Entity
public class TestModelEntity {
@Id
@Type(
type = "pg-uuid"
)
@GeneratedValue(
generator = "uuid2"
)
private UUID id;
@Type(
type = "JSONB",
parameters = { @Parameter(
name = "class",
value = "com.ekino.lombok.sample.Model"
)}
)
private Model model;
….
}
28/39
3.
Alternatives
29/3929/39
Google Auto AutoFactory
JSR-330-compatible factories
AutoService
Provider-configuration files for ServiceLoader
AutoValue
Immutable value-type code generation for Java 1.6+ .
Common
Helper utilities for writing annotation processors.
30/3930/39
AutoValue
• You write an abstract class
• It has abstract accessors, but no fields
• Annotate it with @AutoValue
• Javac generates a concrete subclass for you
• Callers only ever see the parent type
Google Auto
31/3931/39
AutoValue
• What you write (plain Java).
import com.google.auto.value.AutoValue;
@AutoValue
public abstract class Foo {
public static Foo create(String text, int number) {
// defensive copies, preconditions
return new AutoValue_Foo(text, number);
}
/** Documentation here. */
public abstract String text(); // or getText(), if you like
/** Documentation here. */
public abstract int number();
}
Google Auto
32/3932/39
AutoValue
• What code does that generate?
final class AutoValue_Foo extends Foo { // (note: NOT public!)
private final String text;
private final int number;
AutoValue_Foo(String text, int number) {
if (text == null) {
throw new NullPointerException("text");
}
this.text = text;
this.number = number;
}
@Override public String text() {
return text;
}
@Override public int number() {
return number;
}
// and the customary equals/hashCode/toString.
}
Google Auto
33/39
3.
Conclusion
34/3934/39
Advantages
• User writes only plain old Java code
• No runtime impact
• no dependency (@AutoValue has source retention)
• No magical modifying of existing classes
• Still just a single javac pass to compile!
Google Auto
35/3935/39
Disadvantages
• Bootstrap can be annoying—when you first type new AutoValue_Foo it may go
red in the IDE
• Some once-per-project build setup required
• Not support setter for AutoValue
• AutoValue does introduce some fragility.
• The generator has to choose the order of constructor parameters somehow,
so it uses the order in which the accessors appear in the source file.
• This means an innocent refactoring to reorder those accessors could break
your tests
Google Auto
36/3936/39
Advantages
• User writes only plain old Java code
• No runtime impact
• no dependency (annotations has source retention)
• Support delombok
• Maximally concise value classes.
• There is plugin support to integrate with IDE like Lombok plugin for Intellij
Project Lombok
37/3937/39
Disadvantages
• The compiler hacks are non-standard and fragile.
• Somebody may mention that the code is no longer really Java – the code
lose its WYSIWYG feel.
Project Lombok
38/3938/39
• Project Lombok https://projectlombok.org/
• Google Auto https://github.com/google/auto
•http://notatube.blogspot.com/2010/12/project-lombok-creating-custom.html
•http://www.ibm.com/developerworks/library/j-lombok/
•https://docs.google.com/presentation/d/14u_h-
lMn7f1rXE1nDiLX0azS3IkgjGl5uxp5jGJ75RE/edit#slide=id.g2a5e9c4a8_01
39
•The pragmatic programmer - book by Andy Hunt and Dave Thomas
Resources
39/3939/39
Thank you
• LUONG Hoang Nguyen
• Email: hoang-nguyen.luong@ekino.com
• Phone: 0914 974197

More Related Content

What's hot (20)

PPTX
Oop2010 Scala Presentation Stal
Michael Stal
 
PPTX
Qcon2011 functions rockpresentation_scala
Michael Stal
 
PPTX
Core java complete ppt(note)
arvind pandey
 
PDF
Java8
Felipe Mamud
 
ODP
Scala Reflection & Runtime MetaProgramming
Meir Maor
 
PDF
Why Java Sucks and C# Rocks (Final)
jeffz
 
PPTX
Java 8 presentation
Van Huong
 
KEY
Java Performance MythBusters
Sebastian Zarnekow
 
PPTX
Clojure 7-Languages
Pierre de Lacaze
 
PPT
Constructors and destructors in C++ part 2
Lovely Professional University
 
PPT
Java tutorial for Beginners and Entry Level
Ramrao Desai
 
PDF
Code generating beans in Java
Stephen Colebourne
 
PPTX
Java 8 Feature Preview
Jim Bethancourt
 
PPT
Javascript
guest03a6e6
 
PPT
Virtual Function
Lovely Professional University
 
PPT
Introduction to Javascript
Amit Tyagi
 
PDF
JavaScript Programming
Sehwan Noh
 
PPT
Java basic tutorial by sanjeevini india
Sanjeev Tripathi
 
Oop2010 Scala Presentation Stal
Michael Stal
 
Qcon2011 functions rockpresentation_scala
Michael Stal
 
Core java complete ppt(note)
arvind pandey
 
Scala Reflection & Runtime MetaProgramming
Meir Maor
 
Why Java Sucks and C# Rocks (Final)
jeffz
 
Java 8 presentation
Van Huong
 
Java Performance MythBusters
Sebastian Zarnekow
 
Clojure 7-Languages
Pierre de Lacaze
 
Constructors and destructors in C++ part 2
Lovely Professional University
 
Java tutorial for Beginners and Entry Level
Ramrao Desai
 
Code generating beans in Java
Stephen Colebourne
 
Java 8 Feature Preview
Jim Bethancourt
 
Javascript
guest03a6e6
 
Introduction to Javascript
Amit Tyagi
 
JavaScript Programming
Sehwan Noh
 
Java basic tutorial by sanjeevini india
Sanjeev Tripathi
 

Viewers also liked (20)

PDF
Recita: La storia di un nerd – Mario che riprogrammò il pacemaker del presidente
Alessandro Mazzarisi
 
PPTX
ใบงานทที่ 4
Mashmallow Korn
 
PDF
青創沙龍 #6 經濟部 SIIR 服務業創新研發補助:電梯簡報 - 計畫主持人邱婕欣
青年圓夢計劃
 
PPTX
Invest in serbia milano 1 aprile 2015
Strategia e Sviluppo Consultants
 
PDF
Systemic barriers to the fight against corruption new
SYCHRISTO
 
PDF
7 สามัญ คณิต
Mashmallow Korn
 
PDF
Mf0228 3 uf1869 analisi del mercat de productes de comunicacions iii - alumne
Thor Pe
 
PDF
Электронная безопасность и либертарная этика
AutonomousAction
 
PPTX
Buiilding a corruption free society
Onike Rahaman
 
PDF
Sinorides Family amusement park rides for sale-China amusement park rides man...
YU LU
 
PDF
E-commerce in Cina: settore food e cosmetica.
Strategia e Sviluppo Consultants
 
PDF
Cartella Clinica - Aggiornamenti e indirizzi per il futuro
Alessandro Mazzarisi
 
PDF
青創沙龍 #16 創業職涯圓夢十二力:引導力 - 恩卓國際總經理黃同慶
青年圓夢計劃
 
PDF
青創沙龍 #24 創業職涯圓夢十二力:提問力 - 國際教練聯盟台灣總會副理事長賴恆毅
青年圓夢計劃
 
PPT
Чи легко взяти кредит в банку - погляд фермера.
Strategia e Sviluppo Consultants
 
PPT
Аграрні розписки в Україні.
Strategia e Sviluppo Consultants
 
PPTX
Innovation in governance, risk and compliance
Qualsys Ltd
 
PPTX
Проект IFC «Розвиток фінансування аграрного сектору в Європі та Центральній А...
Strategia e Sviluppo Consultants
 
PPTX
E-commerce in Cina: settore food e cosmetica.
Strategia e Sviluppo Consultants
 
PPTX
從學生時代開始,建立求職人脈網絡 by LinkedIn Albert Wang
青年圓夢計劃
 
Recita: La storia di un nerd – Mario che riprogrammò il pacemaker del presidente
Alessandro Mazzarisi
 
ใบงานทที่ 4
Mashmallow Korn
 
青創沙龍 #6 經濟部 SIIR 服務業創新研發補助:電梯簡報 - 計畫主持人邱婕欣
青年圓夢計劃
 
Invest in serbia milano 1 aprile 2015
Strategia e Sviluppo Consultants
 
Systemic barriers to the fight against corruption new
SYCHRISTO
 
7 สามัญ คณิต
Mashmallow Korn
 
Mf0228 3 uf1869 analisi del mercat de productes de comunicacions iii - alumne
Thor Pe
 
Электронная безопасность и либертарная этика
AutonomousAction
 
Buiilding a corruption free society
Onike Rahaman
 
Sinorides Family amusement park rides for sale-China amusement park rides man...
YU LU
 
E-commerce in Cina: settore food e cosmetica.
Strategia e Sviluppo Consultants
 
Cartella Clinica - Aggiornamenti e indirizzi per il futuro
Alessandro Mazzarisi
 
青創沙龍 #16 創業職涯圓夢十二力:引導力 - 恩卓國際總經理黃同慶
青年圓夢計劃
 
青創沙龍 #24 創業職涯圓夢十二力:提問力 - 國際教練聯盟台灣總會副理事長賴恆毅
青年圓夢計劃
 
Чи легко взяти кредит в банку - погляд фермера.
Strategia e Sviluppo Consultants
 
Аграрні розписки в Україні.
Strategia e Sviluppo Consultants
 
Innovation in governance, risk and compliance
Qualsys Ltd
 
Проект IFC «Розвиток фінансування аграрного сектору в Європі та Центральній А...
Strategia e Sviluppo Consultants
 
E-commerce in Cina: settore food e cosmetica.
Strategia e Sviluppo Consultants
 
從學生時代開始,建立求職人脈網絡 by LinkedIn Albert Wang
青年圓夢計劃
 
Ad

Similar to Writing code that writes code - Nguyen Luong (20)

PDF
Hacking Java - Enhancing Java Code at Build or Runtime
Sean P. Floyd
 
PDF
Lombokの紹介
onozaty
 
PPTX
Project Lombok!
Mehdi Haryani
 
PDF
Rocket Propelled Java - Devoxx12
Andres Almiray
 
PDF
Jfokus - Rocket Propelled Java
Andres Almiray
 
PPTX
Use of Apache Commons and Utilities
Pramod Kumar
 
PPTX
Hacking Java @JavaLand2016
Sean P. Floyd
 
ODP
Naïveté vs. Experience
Mike Fogus
 
PDF
Scala for Java Programmers
Eric Pederson
 
PPTX
Proposals for new function in Java SE 9 and beyond
Barry Feigenbaum
 
PDF
Scala for Java Developers
Martin Ockajak
 
PPTX
Fields in Java and Kotlin and what to expect.pptx
João Esperancinha
 
PDF
Polyglot Programming in the JVM - Øredev
Andres Almiray
 
PDF
Atlassian Groovy Plugins
Paul King
 
PDF
Google Guava - Core libraries for Java & Android
Jordi Gerona
 
PDF
Java 5 and 6 New Features
Jussi Pohjolainen
 
ODP
AST Transformations
HamletDRC
 
PPTX
Object Oriented Programming Tutorial.pptx
ethiouniverse
 
PPTX
Java 8 and beyond, a scala story
ittaiz
 
ODP
AST Transformations at JFokus
HamletDRC
 
Hacking Java - Enhancing Java Code at Build or Runtime
Sean P. Floyd
 
Lombokの紹介
onozaty
 
Project Lombok!
Mehdi Haryani
 
Rocket Propelled Java - Devoxx12
Andres Almiray
 
Jfokus - Rocket Propelled Java
Andres Almiray
 
Use of Apache Commons and Utilities
Pramod Kumar
 
Hacking Java @JavaLand2016
Sean P. Floyd
 
Naïveté vs. Experience
Mike Fogus
 
Scala for Java Programmers
Eric Pederson
 
Proposals for new function in Java SE 9 and beyond
Barry Feigenbaum
 
Scala for Java Developers
Martin Ockajak
 
Fields in Java and Kotlin and what to expect.pptx
João Esperancinha
 
Polyglot Programming in the JVM - Øredev
Andres Almiray
 
Atlassian Groovy Plugins
Paul King
 
Google Guava - Core libraries for Java & Android
Jordi Gerona
 
Java 5 and 6 New Features
Jussi Pohjolainen
 
AST Transformations
HamletDRC
 
Object Oriented Programming Tutorial.pptx
ethiouniverse
 
Java 8 and beyond, a scala story
ittaiz
 
AST Transformations at JFokus
HamletDRC
 
Ad

Recently uploaded (20)

PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PDF
July Patch Tuesday
Ivanti
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PDF
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
PDF
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
PDF
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
PDF
Python basic programing language for automation
DanialHabibi2
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PDF
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
PDF
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
PDF
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
PDF
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
July Patch Tuesday
Ivanti
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
Smart Trailers 2025 Update with History and Overview
Paul Menig
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
Using FME to Develop Self-Service CAD Applications for a Major UK Police Force
Safe Software
 
"Beyond English: Navigating the Challenges of Building a Ukrainian-language R...
Fwdays
 
HCIP-Data Center Facility Deployment V2.0 Training Material (Without Remarks ...
mcastillo49
 
Python basic programing language for automation
DanialHabibi2
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Empower Inclusion Through Accessible Java Applications
Ana-Maria Mihalceanu
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Chris Elwell Woburn, MA - Passionate About IT Innovation
Chris Elwell Woburn, MA
 
From Code to Challenge: Crafting Skill-Based Games That Engage and Reward
aiyshauae
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
HubSpot Main Hub: A Unified Growth Platform
Jaswinder Singh
 
CIFDAQ Market Insights for July 7th 2025
CIFDAQ
 
Agentic AI lifecycle for Enterprise Hyper-Automation
Debmalya Biswas
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 

Writing code that writes code - Nguyen Luong

  • 1. 1/39 Writing code that writes code by LUONG Hoang Nguyen Senior Java Technical Lead ekino.
  • 2. 2/392/39 1. Context 2. Project Lombok 3. Alternatives 4. Conclusion AGENDA
  • 4. 4/394/39 Developer job As programmers, we often find ourselves in a similar position. We need to achieve the same functionality, but in different contexts. We need to repeat information in different places. Sometimes we just need to protect ourselves from carpal tunnel syndrome by cutting down on repetitive typing
  • 5. 5/395/39 Boiler Plate Code Syntax Verbosity Problemsof theIndustry Non Standardization Not following the standard code conventions Human Error/Dependency Repeatable things (defining Getters, Setters etc.)
  • 9. 9/399/39 @Getter / Setter Features • Automatic Generation of getters and setters. • Method will be public unless you explicitly specify an AccessLevel • @Getter and/or @Setter annotation on class • Disable getter/setter generation for any field by using the special AccessLevel.NONE • @NotNull for nullity check
  • 10. 10/3910/39 import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class GetterSetterExample { /** * Age of the person. Water is wet. * * @param age New value for this person's age. Sky is blue. * @return The current value of this person's age. Circles are round. */ @Getter @Setter private int age = 10; /** * Name of the person. * -- SETTER -- * Changes the name of this person. * * @param name The new value. */ @Setter(AccessLevel.PROTECTED) private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); } } public class GetterSetterExample { /** * Age of the person. Water is wet. * * @param age New value for this person's age. Sky is blue. * @return The current value of this person's age. Circles are round. */ private int age = 10; /** * Name of the person. * -- SETTER -- * Changes the name of this person. * * @param name The new value. */ private String name; @Override public String toString() { return String.format("%s (age: %d)", name, age); } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } protected void setName(String name) { this.name = name; } }
  • 11. 11/3911/39 @EqualsAndHash Code Features • Generates hashCode and equals implementations from the fields (non- static, non-transient) • Parameters 
  • 12. 12/3912/39 import lombok.EqualsAndHashCode; @EqualsAndHashCode(exclude = { "id", "shape" }) class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private Shape shape = new Square(5, 10); private String[] tags; private int id; public String getName() { return this.name; } } public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private Shape shape = new Square(5, 10); private String[] tags; private int id; public String getName() { return this.name; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof EqualsAndHashCodeExample)) { return false; } final EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o; if (!other.canEqual((Object) this)) { return false; } final Object this$name = this.getName(); final Object other$name = other.getName(); if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (Double.compare(this.score, other.score) != 0) { return false; } if (!java.util.Arrays.deepEquals(this.tags, other.tags)) { return false; } return true; } public int hashCode() { final int PRIME = 59; int result = 1; final Object $name = this.getName(); result = result * PRIME + ($name == null ? 0 : $name.hashCode()); final long $score = Double.doubleToLongBits(this.score); result = result * PRIME + (int) ($score >>> 32 ^ $score); result = result * PRIME + java.util.Arrays.deepHashCode(this.tags); return result; } protected boolean canEqual(Object other) { return other instanceof EqualsAndHashCodeExample; } }
  • 13. 13/3913/39 @Data Features • All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor • Included annotations with changed parameters can be defined along with @Data
  • 14. 14/3914/39 import lombok.Data; @Data public class DataExample { private final String name; private double score; } public class DataExample { private final String name; private double score; @java.beans.ConstructorProperties({ "name" }) public DataExample(String name) { this.name = name; } public String getName() { return this.name; } public double getScore() { return this.score; } public void setScore(double score) { this.score = score; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof DataExample)) { return false; } final DataExample other = (DataExample) o; if (!other.canEqual((Object) this)) { return false; } final Object this$name = this.name; final Object other$name = other.name; if (this$name == null ? other$name != null : !this$name.equals(other$name)) { return false; } if (Double.compare(this.score, other.score) != 0) { return false; } return true; } public int hashCode() { final int PRIME = 59; int result = 1; final Object $name = this.name; result = result * PRIME + ($name == null ? 0 : $name.hashCode()); final long $score = Double.doubleToLongBits(this.score); result = result * PRIME + (int) ($score >>> 32 ^ $score); return result; } protected boolean canEqual(Object other) { return other instanceof DataExample; } public String toString() { return "DataExample(name=" + this.name + ", score=" + this.score + ")"; } }
  • 15. 15/3915/39 @NoArgsConstructor @RequiredArgsConstructor @AllArgsConstructor Features • Generates constructors that take no arguments, one argument per final / non-null field, or one argument for every field. • Specialized constructor can be made. Compile-time error in case of any conflicts.
  • 16. 16/3916/39 @Cleanup Features • Automatic resource management: Call your close() methods safely with no hassle. @Cleanup InputStream in=new FileInputStream("some/file"); • If the type of object you'd like to cleanup does not have a close() method, but some other no-argument method like dispose() so write it as @Cleanup("dispose") TestClass t = new TestClass();
  • 17. 17/3917/39 @Builder val Features • @Builder generates a static builder() method that returns a builder instance. This builder instance can be used to build an object of the class annotated with @Builder (here Person) • Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build(); • val: You can use val as the type of a local variable declaration instead of actually writing the type. This feature works on local variables and on foreach loops only, not on fields val example = new ArrayList<String>(); example.add("Hello, World!");
  • 18. 18/3918/39 import lombok.Builder; @Builder public class BuilderExample { private String name; private int age; } public class BuilderExample { private String name; private int age; @java.beans.ConstructorProperties({ "name", "age" }) BuilderExample(String name, int age) { this.name = name; this.age = age; } public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } public static class BuilderExampleBuilder { private String name; private int age; BuilderExampleBuilder() { } public BuilderExample.BuilderExampleBuilder name(String name) { this.name = name; return this; } public BuilderExample.BuilderExampleBuilder age(int age) { this.age = age; return this; } public BuilderExample build() { return new BuilderExample(name, age); } public String toString() { return "BuilderExampleBuilder(name=" + this.name + ", age=" + this.age + ")"; } } }
  • 19. 19/3919/39 • Generates Java Boilerplate • Compile Time Only -> not affect performance for runtime • For Eclipse and javac • IntelliJ IDEA & NetBeans too • Removable with delombok • Know what is generated Features
  • 20. 20/3920/39 How does it work? Java compilation has 3 stages: In the Parse and Enter phase, the compiler parses source files into an Abstract Syntax Tree (AST In the Annotation Processing phase, custom annotation processors are invoked Annotation processors can do things like validate classes or generate new resources, including source files. In the last phase, Analyse and Generate, the compiler generates class files (byte code) from the Abstract Syntax Trees generated in phase 1 Project Lombok hooks itself into the compilation process as an annotation processor. Normally, annotation processors only generate new source files whereas Lombok modifies existing classes.
  • 21. 21/3921/39 Example • Example we create a very simple Lombok transformation that adds a helloWorld method to any class annotated as @HelloWorld. • The basic classes we need to write are: - Annotation class - Eclipse handler - Javac handler (Intellj also supported this) @HelloWorld public class MyClass { } public class MyClass { public void helloWorld() { System.out.println("Hello World"); } }
  • 22. 22/3922/39 Annotation Example • At first, we just need to create an annotation called HelloWorld that can be applied to classes. import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) public @interface HelloWorld { }
  • 23. 23/3923/39 Handler Example • Our handler will be adding a new Method Declaration to the Type Declaration. A Method Declaration is composed of several components. The AST for our Method Declaration will have this :
  • 24. 24/3924/39 Handler Logic Example • Our handle method will need to do the following: 1. Mark annotation as processed 2. Create the helloWorld method 3. Inject the helloWorld method into the AST of the annotated class
  • 25. 25/3925/39 Lombok provides our handler with the AST of the annotation node. We know that the annotation can only be applied to a Type. To get the AST for the Type (Class), we call annotationNode.up(). The annotation is a child of the Type AST, so by calling up() we get the parent AST which is the Type AST we need to modify. Javac Handler Example @ProviderFor(JavacAnnotationHandler.class) public class HandleHelloWorld implements JavacAnnotationHandler<HelloWorld>{ public boolean handle(AnnotationValues<HelloWorld> annotation, JCAnnotation ast, JavacNode annotationNode) { JavacHandlerUtil.markAnnotationAsProcessed(annotationNode, HelloWorld.class); JavacNode typeNode = annotationNode.up(); if(notAClass(typeNode)) { annotationNode.addError("@HelloWorld is only supported on a class."); return false; } JCMethodDecl helloWorldMethod = createHelloWorld(typeNode); JavacHandlerUtil.injectMethod(typeNode, helloWorldMethod); return true; } … }
  • 26. 26/3926/39 • Start with a method node. • Add the return type, parameters, access level, throw clause, etc to the method node. • Create an expression statement to represent System.out.println("Hello World") • Add the expression to the method node. Javac Handler Hello world method Example private JCMethodDecl createHelloWorld(JavacNode type) { TreeMaker treeMaker = type.getTreeMaker(); JCModifiers modifiers = treeMaker.Modifiers(Modifier.PUBLIC); List<JCTypeParameter> methodGenericTypes = List.<JCTypeParameter>nil(); JCExpression methodType = treeMaker.TypeIdent(TypeTag.VOID); Name methodName = type.toName("helloWorld"); List<JCVariableDecl> methodParameters = List.<JCVariableDecl>nil(); List<JCExpression> methodThrows = List.<JCExpression>nil(); JCExpression printlnMethod = JavacHandlerUtil.chainDots(treeMaker, type, "System", "out", "println"); List<JCExpression> printlnArgs = List.<JCExpression>of(treeMaker.Literal("hello world")); JCMethodInvocation printlnInvocation = treeMaker.Apply(List.<JCExpression>nil(), printlnMethod, printlnArgs); JCBlock methodBody = treeMaker.Block(0, List.<JCStatement>of(treeMaker.Exec(printlnInvocation))); JCExpression defaultValue = null; return treeMaker.MethodDef( modifiers, methodName, methodType, methodGenericTypes, methodParameters, methodThrows, methodBody, defaultValue ); }
  • 27. 27/3927/39 @UUIDColumn @JsonColumn Custom Annotations • We can create custom annotations that helpful for our projects. It will make standardization for our coding. @Entity @Data public class TestModelEntity { @Id @UUIDColumn private UUID id; @JsonColumn private Model model; …. } @Entity public class TestModelEntity { @Id @Type( type = "pg-uuid" ) @GeneratedValue( generator = "uuid2" ) private UUID id; @Type( type = "JSONB", parameters = { @Parameter( name = "class", value = "com.ekino.lombok.sample.Model" )} ) private Model model; …. }
  • 29. 29/3929/39 Google Auto AutoFactory JSR-330-compatible factories AutoService Provider-configuration files for ServiceLoader AutoValue Immutable value-type code generation for Java 1.6+ . Common Helper utilities for writing annotation processors.
  • 30. 30/3930/39 AutoValue • You write an abstract class • It has abstract accessors, but no fields • Annotate it with @AutoValue • Javac generates a concrete subclass for you • Callers only ever see the parent type Google Auto
  • 31. 31/3931/39 AutoValue • What you write (plain Java). import com.google.auto.value.AutoValue; @AutoValue public abstract class Foo { public static Foo create(String text, int number) { // defensive copies, preconditions return new AutoValue_Foo(text, number); } /** Documentation here. */ public abstract String text(); // or getText(), if you like /** Documentation here. */ public abstract int number(); } Google Auto
  • 32. 32/3932/39 AutoValue • What code does that generate? final class AutoValue_Foo extends Foo { // (note: NOT public!) private final String text; private final int number; AutoValue_Foo(String text, int number) { if (text == null) { throw new NullPointerException("text"); } this.text = text; this.number = number; } @Override public String text() { return text; } @Override public int number() { return number; } // and the customary equals/hashCode/toString. } Google Auto
  • 34. 34/3934/39 Advantages • User writes only plain old Java code • No runtime impact • no dependency (@AutoValue has source retention) • No magical modifying of existing classes • Still just a single javac pass to compile! Google Auto
  • 35. 35/3935/39 Disadvantages • Bootstrap can be annoying—when you first type new AutoValue_Foo it may go red in the IDE • Some once-per-project build setup required • Not support setter for AutoValue • AutoValue does introduce some fragility. • The generator has to choose the order of constructor parameters somehow, so it uses the order in which the accessors appear in the source file. • This means an innocent refactoring to reorder those accessors could break your tests Google Auto
  • 36. 36/3936/39 Advantages • User writes only plain old Java code • No runtime impact • no dependency (annotations has source retention) • Support delombok • Maximally concise value classes. • There is plugin support to integrate with IDE like Lombok plugin for Intellij Project Lombok
  • 37. 37/3937/39 Disadvantages • The compiler hacks are non-standard and fragile. • Somebody may mention that the code is no longer really Java – the code lose its WYSIWYG feel. Project Lombok
  • 38. 38/3938/39 • Project Lombok https://projectlombok.org/ • Google Auto https://github.com/google/auto •http://notatube.blogspot.com/2010/12/project-lombok-creating-custom.html •http://www.ibm.com/developerworks/library/j-lombok/ •https://docs.google.com/presentation/d/14u_h- lMn7f1rXE1nDiLX0azS3IkgjGl5uxp5jGJ75RE/edit#slide=id.g2a5e9c4a8_01 39 •The pragmatic programmer - book by Andy Hunt and Dave Thomas Resources
  • 39. 39/3939/39 Thank you • LUONG Hoang Nguyen • Email: [email protected] • Phone: 0914 974197