Last week we looked at Java 14 records as a way to easily create immutable data classes to use as DTOs (data transfer objects). This week we’re going to look at doing something similar for mutable domain objects.
It’s normally necessary to create a canonical class for each domain object in our design. But writing all the code for these classes can be quite tedious. Imagine that we have a large number of domain classes in our design. To create a canonical class for each one of them will entail a huge amount of repetitive coding.
Project Lombok (https://projectlombok.org/) comes to the rescue!
What is Project Lombok?
Project Lombok is a small third party library that we add to the CLASSPATH
. Lombok defines a number of annotations and associated annotation processors. These annotations are used to annotate our domain classes appropriately, instructing the annotation processors to generate any necessary boilerplate code. This turns a simple data structure into a canonical class.
The annotations include:
@Getter
/@Setter
@ToString
@EqualsAndHashCode
@NoArgsConstructor
defines the default no-argument constructor@RequiredArgsConstructor
defines a constructor with an argument for each final or non-null field@AllArgsConstructor
defines a constructor with one argument for every field@Data
is a shortcut for a@Getter
on every field, a@Setter
on all non-final fields,@ToString
,@EqualsAndHashCode
and@RequiredArgsConstructor
Implementation
We would use the annotations as follows:
import lombok.*; @Data @NoArgsConstructor @AllArgsConstructor public class Person { // simple data structure with no additional code private String name; private int age; private Gender gender; } // end of class
Download the lombok.jar
file at https://projectlombok.org/download. Once we’ve added it to the CLASSPATH
, we’re ready to go.
Generated Code
Once we’ve compiled the code, we can run the JDK javap
disassembler on the Person.class
file. The default output of javap
is the following:
public class Person { public java.lang.String getName(); public int getAge(); public Gender getGender(); public void setName(java.lang.String); public void setAge(int); public void setGender(Gender); public boolean equals(java.lang.Object); protected boolean canEqual(java.lang.Object); public int hashCode(); public java.lang.String toString(); public Person(); public Person(java.lang.String, int, Gender); }
As we can see, we now have a default no-argument constructor, a constructor with a parameter for each of the three defined fields, appropriate getters and setters (using the JavaBeans naming convention), as well as the equals()
, hashCode()
, and toString()
methods.
We’re not compelled to have Lombok generate all the code. We can choose to create our own constructors or equals()
and hashCode()
methods, if we so choose.
To see what code the Lombok annotations actually generate, go to http://www.javadecompilers.com/, choose just about any decompiler (depending on the Java version being used), and upload the compiled Person
class. The resulting code may or may not be what we would like for our canonical classes.
Lombok vs IDE Code Generation
If we’re using a modern IDE, it can also generate code for domain classes. A problem with actual code generation is that the code is physically there in the project. We can see what’s generated, but we also have a lot more code to wade through when maintaining and modifying code.
If we add extra fields to our class, the IDE doesn’t automatically re-generate the code. Lombok doesn’t generate Java code – it generates bytecodes on the fly. So the simple data structure that we created earlier is the only code we need to see.
Conclusion
Using Project Lombok can lead to much faster coding for domain classes, with a lot less code to maintain and wade through. It is currently used in a large number of enterprise applications.
This post is not necessarily an endorsement of Project Lombok, though personally I think it’s very cool! It’s to introduce the possibility of using it in a project if it suits our needs.
As always, please share your comments and questions.