Skip to main content

Project Lombok : The Boilerplate Code Extractor

Lombok is a tool that generates code like getters, setters, constructors, equals, hashCode, toString for us in the same way that our IDE does. While IDE generates all these things in our source code file, Lombok generates them directly in the class file.

So Lombok basically takes out all these things from your source code to bytecode so we don't need to write them in our source code which means less code in our source code file. And in this article, I am going to explain how Lombok can help us in removing this kind of boilerplate code.

To understand it let's suppose we have an entity class Employee and we want to use it to hold a single employee record. We can use it as a DTO or persistent entity or anything else we want but idea is that we want to use it to store id, firstName, lastName and salary fields.

For this requirement, we will need a simple Employee POJO and according to General directions for creating Plain Old Java Object,
  • Each variable in a POJO should be declared as private.
  • Default constructor should be overridden with public accessibility.
  • Each variable should have its Setter-Getter method with public accessibility.
  • POJO should override equals(), hashCode() and toString() methods of Object.
And generally our Employee class will look like

public class Employee {
private long id;
private int salary;
private String firstName;
private String lastName;

public Employee() {
}

public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Employee employee = (Employee) o;

if (id != employee.id) return false;
if (salary != employee.salary) return false;
if (!firstName.equals(employee.firstName)) return false;
if (!lastName.equals(employee.lastName)) return false;

return true;
}

@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + firstName.hashCode();
result = 31 * result + lastName.hashCode();
result = 31 * result + salary;
return result;
}

@Override
public String toString() {
return "Employee{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", salary=" + salary +
'}';
}
}

But generally, we always use auto-generation strategies of our IDE to generate getters, setters, default constructor, hashCode, equals and toString e.g. alt+insert in IntelliJ.

As you can see the size of Employee class is more than 50 lines where field declaration is contributing only 4 lines. And these things are not directly contributing anything to our business logic but just increasing the size of our code.

Project Lombok provides a way to remove above boilerplate code and simplify development process while still providing these functionalities at the bytecode level. With project Lombok, we can combine all these things within 10 lines

@Data
public class Employee {
private long id;
private int salary;
private String firstName;
private String lastName;
}

With @Data annotation on top of our class Lombok will process our Java source code and produce a class file which will have getters, setters, default arg constructor, hasCode, equals and toString methods in it. So basically Lombok is doing the trick and instead of us adding all those things in our source code and then compiling it a class file Lombok is automatically adding all these things directly to our class files.

But if we need to write some business code in our getters or setters or in any of above method or we want trick these methods to function a little bit differently, we can still write that method in our class and Lombok will not override it while producing all these stuff in bytecode.

In order to make it works, we need to
  1. Install Lombok plugin in our IDE e.g. In IntelliJ we can install it from Settings -> Plugins -> Browse Repositories window.installing-lombok-plugin-in-intellij-idea
  2. Enable annotation processing e.g. In IntelliJ we need to check “Enable annotation processing” option on Settings -> Compiler -> Annotation Processors window.enabling-annotation-in-intellij-idea
  3. Include Lombok jar in our build path, we can do it by adding the Lombok dependency in pom.xml file if we are using maven or we will need to download the Lombok jar manually and add it to our classpath.
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.12</version>
    <optional>true</optional>
    <dependency>
Lombok provides a variety of annotations which we can use and manipulate according to our need. Some of these annotations are
  • @NonNull Can be used with fields, methods, parameters, and local variables to check for NullPointerException.
  • @Cleanup Provides automatic resource management and ensures the variable declaration that you annotate will be cleaned up by calling its close method. Seems similar to Java’s try-with-resource.
    @Cleanup InputStream in = new FileInputStream("filename");
  • @Getter/@Setter Can be used on class or field to generate getters and setters automatically for every field inside the class or for a particular field respectively.
    @Getter @Setter private long id;
  • @ToString Generates a default toString method
  • @EqualsAndHashCode Generates hashCode and equals implementations from the fields of your object.
    @ToString(exclude = "salary")
    @EqualsAndHashCode(exclude = "salary")
  • @NoArgsConstructor , @RequiredArgsConstructor and @AllArgsConstructor Generates constructors that take no arguments, one argument per final / non-null field, or one argument for every field.
  • @Data A shortcut for @ToString , @EqualsAndHashCode , @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor .
  • @Value is the immutable variant of @Data, Helps in making our class Immutable.
  • @Builder annotation will generate nice static factory methods in our class which we can use to create objects of our class in more oriented manner e.g. if we will add “@Builder” annotation to our Employee class then we can create object of Employee in the following manner
    Employee emp = Employee.builder()
    .firstName("Naresh")
    .lastName("Joshi")
    .build();
  • @SneakyThrows Allows us to throw checked exceptions without actually declaring this in our method’s throws clause, e.g.
    @SneakyThrows(Exception.class)
    public void doSomeThing() {
    // According to some business condition throw some business exception
    throw new Exception();
    }
  • @Synchronized A safer variant of the synchronized method modifier.
  • @CommonsLog, @JBossLog, @Log, @Log4j, @Log4j2, @Slf4j and @XSlf4j which produces log fields in our class and let us use that field for logging. e.g. If we will mark a class with @CommonsLog Lombok will attach below field to our class.
    private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(YourClass.class);
You can also go to the official website of project Lombok for the complete feature list and examples.

Advantages of Lombok

  • Lombok helps us remove boilerplate code and decrease line of unnecessary code
  • It makes our code highly maintainable, we don’t need to worry about regenerating hashCode, equals, toString, getters, and setters whenever we change our properties.
  • Lombok provides an efficient builder API to build our object by using @Builder
  • Lombok provides efficient way to make our class Immutable by using @Value
  • Provides other annotations like @Log - for logging, @Cleanup - for cleaning resources automatically, @SneakyThrows  - for throwing checked exception without adding try-catch or throws statement and @Synchronized to make our methods synchronized.

Disadvantages of Lombok

The only disadvantage Lombok comes with is its dependency, If you are using it then everyone in your project must use it and configure it (install the plugin and enable annotation processing) to successfully compile the project. And all your project mates need to be aware of it otherwise, they will not be able to build the project and receive lots of compilation errors. However, this is only an initial step and will not take more than a couple of minutes.

Comments

Post a Comment

Popular posts from this blog

Why an outer Java class can’t be static

In a previous blog , I talked about why we can not define an outer class using private or protected keywords. If you have not read it, please go ahead and give it a look. I this article I will talk what is the use of the static keyword, why an outer Java class can’t be static, why it is not allowed in Java to define a static outer class. In order to understand that first, we need to understand what is the static keyword used for, what purpose it solves and how does it works. What does static keyword do Every Java programmer knows that if we need to define some behavior (method) or state (field) which will be common to all objects we define it as static. Because static content (behavior or state) does not belong to any particular instance or object, it will common to all objects and all objects are free to change any static field and every change will be visible to every object. We do not need to create any object of the class to access a static field or method, we can directly...

Why Single Java Source File Can Not Have More Than One public class

According to Java standards and common practices we should declare every class in its own source file. And even if we declare multiple classes in the single source file (.java) still each class will have its own class file after compilation. But the fact is that we can declare more than one class in a single source file with below constraints, Each source file should contain only one public class and the name of that public class should be similar to the name of the source file. If you are declaring the main method in your source file then main should lie in that public class If there is no public class in the source file then main method can lie in any class and we can give any name to the source file. If you are not following 1st constraint then you will receive a compilation error saying “ The public type A must be defined in its own file ”.  While if you are not following the second constraint you will receive an error “ Error: Could not find or load main class User ” after ...

How Does JVM Handle Method Overloading and Overriding Internally

In my previous article Everything About Method Overloading Vs Method Overriding , I have discussed method overloading and overriding, their rules and differences. In this article, we will see How Does JVM Handle Method Overloading And Overriding Internally, how JVM identifies which method should get called. Let’s take the example of parent class  Mammal and a child  Human classes from our previous blog to understand it more clearly. public class OverridingInternalExample { private static class Mammal { public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); } } private static class Human extends Mammal { @Override public void speak() { System.out.println("Hello"); } // Valid overload of speak public void speak(String language) { if (language.equals("Hindi")) System.out.println("Namaste"); else System.out.println("Hello"); } @...