Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Project Lombok: The Boilerplate Code Extractor

DZone's Guide to

Project Lombok: The Boilerplate Code Extractor

Lombok can be a huge space saver for your projects by generating boilerplate code directly in your class file. See how it works and the many annotations at your disposal.

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

Lombok is a tool that generates code for things like getters, setters, constructors, equals, hashCode, and toString for us in the same way that our IDE does. While an 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, which means a smaller 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 the 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 the General directions for creating Plain Old Java Objects:

  • Each variable in a POJO should be declared as private.
  • Default constructors should be overridden with public accessibility.
  • Each variable should have its Setter-Getter method with public accessibility.
  • A 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 the 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 the Employee class is more than 50 lines, while field declaration is contributing only 4 lines. And these things are not directly contributing anything to our business logic, just increasing the size of our code.

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

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


With the @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 to 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 the 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 this stuff in bytecode.

In order to make it works, we need to:

  1. Install the Lombok plugin in our IDE — e.g. In IntelliJ, we can install it from Settings -> Plugins -> Browse Repositories.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.enabling-annotation-in-intellij-idea
  3. Include the Lombok JAR in our build path. We can do that by adding the Lombok dependency in the 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 that we can use and manipulate according to our needs. Some of these annotations are:

  • @NonNull: Can be used with fields, methods, parameters, and local variables to check for NullPointerExceptions.
  • @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 a 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. It helps in making our class Immutable. 
  • The @Builder annotation will generate nice static factory methods in our class, which we can use to create objects of our class in a more oriented manner — e.g. if we will add the “@Builder” annotation to our Employee class, then we can create an 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:
    @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: Produces log fields in our class and lets us use that field for logging. For example, if we mark a class with @CommonsLog, Lombok will attach the 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 lines 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, and @SneakyThrows for throwing checked exceptions without adding try-catch or throw statements, 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.

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
java ,lombok ,boilerplate ,annotations ,tutorial

Published at DZone with permission of Naresh Joshi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}