Introduction to lombok
Posted By : Simran Ahuja | 28-Jun-2021
Introduction to Project Lombok
1. Avoid Repetitive Code
Java is a very great language, but it can also sometimes get too expansive for common tasks we have to do in our code or compliance with some framework practices. This often doesn't bring any real value to the business side of our programs, and that's where Lombok comes in to make us more productive and efficient.
The way it works is by plugging into our build process and auto-generating Java bytecode into our .class files as per a number of project annotations we introduce and use in our code.
Including it in our builds, in whichever or whatever system we're using, is very straight forward. Most of my projects are maven based, so I just basically drop their dependency in the provided scope and I'm good to go:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency>
2. Getters/Setters, Constructors – So Repetitive
Encapsulating object properties via public getter and setter methods is such a common practice in the our Java world, and lots of frameworks rely on this pattern of “Java Bean” extensively (a class with an empty constructor and get/set methods for its “properties”).
This is so common that most IDE's support auto-generating code for these patterns (and more) by just click on generate getters and setters . However, this code needs to live in our sources and be maintained whenever we add a new property is added or a field renamed.
By adding the such annotaions like @Getter and @Setter annotations, we told Lombok to generate these for all of the fields of the class. @NoArgsConstructor will lead to generating an empty constructor .
If we further add new attributes (properties) to our User class the same will happen we apply the annotations to the type itself so they will keep in mind all fields by default and we don't have to worry.
What if we want to refine the visibility of only some properties? For example, if we want to keep our entities' id field modifiers package or protected visible because they are expected to be only read, but not explicitly set by application code, we can just use a finer grained @Setter for this particular field:
private @Id @Setter(AccessLevel.PROTECTED) Long id;
3. Lazy Getter
Applications often need to perform expensive operations and also save the results for subsequent use.
For instance, let's say we need to read static data from a file or even a database. It's generally good practice to retrieve this data once, and then cache it to allow in-memory reads within the application fro better performace. This saves the application from repeating the expensive operation and saves time.
Another common pattern is to retrieve this data only when it's first needed or required. In other words, we only and only get the data when we call the corresponding getterfor the varianle the first time. We call this process as lazy-loading.
Let's imagine that this data is cached as a field inside a class. The class must now make sure that any access to this field returns only the cached data. One possible way to implement such a class is to make the getter method retrieve the data only if the field is with value null. this is called as a lazy getter.
@Getter(lazy = true) private final Map<String, Long> transaction = getTransactions();
4. Value Classes/DTO's
There are many situations in which we want to define a data type with the sole purpose of representing our complex “values” as “Data Transfer Objects,” most of the time in the form of immutable data structures we build once and never want to change them.
We design a class to represent a successful operation called login operation. We want all fields to be non-null and objects should be immutable so that we can thread-safely access its properties:
Once we add the @RequiredArgsConstructor annotation, we'll thus get a constructor for all the final fields int the class, just as we declared them. Adding @NonNull to attributes makes our constructor check for nullability and thus throw NullPointerExceptions accordingly. This would also happen if the fields were non-final and we marked @Setter for them.
5. Core Java Boilerplate
Another situation where we end up writing code we need to maintain is while generating the toString(), equals() and hashCode() methods. IDEs also try to help with templates for auto-generating these in terms of our class attributes.
We can automate this by means of other Lombok class-level annotations which are:
- @ToString: will generate a toString() method including all class attributes and then there is no need to write one ourselves and maintain it as we enrich our data model.
- @EqualsAndHashCode: will generate both equals() and hashCode() methods by default considering all of the relevant fields, and according to very well though semantics.