Project Lombok complete guide: From None to One!

Play this article

Introduction

In Java programming, developers often need to write boilerplate code for simple tasks like getter/setter methods, constructors, equals, and hashcode methods, etc. Writing such code repeatedly can be time-consuming and error-prone, leading to reduced productivity. Project Lombok is a Java library that helps to reduce boilerplate code by providing a set of annotations that can be added to Java classes. This library generates the boilerplate code at compile-time, reducing the amount of manual coding required by the developer.

Explanation of Boilerplate Code:

Boilerplate code is a term used to describe code that is repetitive, verbose, and adds little value to the overall functionality of the code. In Java programming, developers often write boilerplate code for simple tasks like creating getters/setters, constructors, equals, and hashcode methods. This code is required to be written repeatedly for every class and can take up a significant amount of time.

How Lombok helps to reduce it?

Lombok helps to reduce boilerplate code by providing a set of annotations that can be added to Java classes. These annotations generate the code at compile-time, reducing the amount of manual coding required by the developer. For example, the @Getter and @Setter annotations generate getter/setter methods for all fields in a class. Similarly, the @ToString annotation generates a toString() method, and the @NoArgsConstructor annotation generates a no-argument constructor.

Overview of Project Lombok:

Project Lombok is a Java library that helps to reduce boilerplate code by providing a set of annotations that can be added to Java classes. The library is open-source and can be easily integrated into existing Java projects. The annotations provided by Lombok include:

  • @Getter and @Setter for generating getter/setter methods

  • @ToString for generating a toString() method

  • @EqualsAndHashCode for generating equals() and hashCode() methods

  • @NoArgsConstructor, @RequiredArgsConstructor, and @AllArgsConstructor for generating constructors

  • @Data for generating all of the above methods together

  • @Slf4j for generating a logger object for a class

Lombok has gained popularity among Java developers due to its ability to reduce boilerplate code and increase productivity.

Getting Started

1. Installation of Lombok

To start using Project Lombok, you need to first install it. There are several ways to install Lombok, but the most common one is through Maven or Gradle.

Installing Lombok with Maven

To install Lombok with Maven, add the following dependency to your pom.xml file:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
</dependency>

Installing Lombok with Gradle

To install Lombok with Gradle, add the following dependency to your build.gradle file:

dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'
}

2. Setting up Lombok in the IDE

After installing Lombok, you need to set it up in your IDE. Below are instructions for setting up Lombok in popular IDEs like IntelliJ IDEA, Eclipse, and VSCode.

Setting up Lombok in IntelliJ IDEA

  1. Open IntelliJ IDEA and navigate to File > Settings.

  2. In the Settings window, go to Build, Execution, Deployment > Compiler > Annotation Processors.

  3. Check the box next to "Enable annotation processing".

  4. Under "Annotation Processors", click the "+" button to add a new annotation processor.

  5. In the "Create New Annotation Processor" window, enter the following information:

    • Name: Lombok

    • Processor path: [path_to_lombok_jar]/lombok-1.18.20.jar

    • Output directory: [path_to_project]/target/generated-sources/lombok

    • Processor options: lombok.addLombokGeneratedAnnotation=true

  6. Click "OK" to save the new annotation processor.

  7. Close the Settings window and rebuild your project.

Setting up Lombok in Eclipse

  1. Open Eclipse and navigate to Window > Preferences.

  2. In the Preferences window, go to Java > Compiler > Annotation Processing.

  3. Check the box next to "Enable annotation processing".

  4. Under "Factory Path", click the "Add External JARs" button and select the Lombok JAR file (lombok-1.18.20.jar).

  5. Click "Apply and Close" to save the changes.

  6. Rebuild your project.

Setting up Lombok in VSCode

  1. Install the Lombok plugin for VSCode.

  2. Open your project in VSCode and go to the Settings tab.

  3. Search for "lombok.config.path" and set the value to ${workspaceFolder}/lombok.config.

  4. Create a new file named lombok.config in the root directory of your project.

  5. Add the following line to the lombok.config file: lombok.addLombokGeneratedAnnotation=true.

  6. Save the lombok.config file and rebuild your project.

Lombok Annotations:

@Getter and @Setter annotations:

The @Getter and @Setter annotations are used to automatically generate getter and setter methods for the fields of a class. For example:

@Getter @Setter
public class Person {
    private String name;
    private int age;
}

This generates the following code:

public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

@ToString annotation:

The @ToString annotation generates a toString() method for a class. It can be used to print out the contents of an object for debugging purposes. For example:

@ToString
public class Person {
    private String name;
    private int age;
}

This generates the following code:

public class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person(name=" + name + ", age=" + age + ")";
    }
}

@EqualsAndHashCode annotation:

The @EqualsAndHashCode annotation generates equals() and hashCode() methods for a class based on its fields. It can be used to compare objects for equality. For example:

@EqualsAndHashCode
public class Person {
    private String name;
    private int age;
}

This generates the following code:

public class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

@NoArgsConstructor, @RequiredArgsConstructor, and @AllArgsConstructor annotations:

These annotations generate constructors for a class. @NoArgsConstructor generates a constructor with no arguments, @RequiredArgsConstructor generates a constructor with arguments for all final fields, and @AllArgsConstructor generates a constructor with arguments for all fields. For example:

@NoArgsConstructor
@RequiredArgsConstructor
@AllArgsConstructor
public class Person {
    private final String name;
    private int age;
}

This generates the following constructors:

public class Person {
    private final String name;
    private int age;

    public Person() {}

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

@Data Annotation

The @Data annotation is a shortcut for creating all the getters, setters, equals(), hashCode(), and toString() methods in a single annotation. Instead of writing all of those methods for each class, we can simply add @Data to our class and Lombok will generate them for us.

For example, consider the following class:

@Data
public class User {
    private Long id;
    private String firstName;
    private String lastName;
}

With the @Data annotation, Lombok will generate the following methods:

  • getId(), setId(Long id)

  • getFirstName(), setFirstName(String firstName)

  • getLastName(), setLastName(String lastName)

  • equals(Object obj)

  • hashCode()

  • toString()

@Builder Annotation

The @Builder annotation generates a builder class for us. This builder class makes it easier to create objects with a large number of fields, especially when many of those fields are optional. We can set only the fields that we care about and leave the others as their default values.

For example, consider the following class:

@Data
@Builder
public class User {
    private Long id;
    private String firstName;
    private String lastName;
    private Integer age;
    private String email;
    private String phone;
}

With the @Builder annotation, we can create a User object like this:

User user = User.builder()
                .firstName("John")
                .lastName("Doe")
                .age(30)
                .email("john.doe@example.com")
                .build();

Notice that we only set the fields that we care about, and leave the others as their default values. The build() method creates the User object for us. We can also chain the setters together to create the object in a single line of code.

@Log and @Slf4j annotations:

The @Log and @Slf4j annotations are used to generate a logger field in the annotated class. @Log is a shortcut for @CommonsLog, @Log4j, @Log4j2, or @Slf4j, depending on the availability of the corresponding logging framework. @Slf4j is equivalent to @Log4j2 in functionality, but it uses the Simple Logging Facade for Java (SLF4J) framework instead of Log4j 2.

Example:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyClass {
    public void myMethod() {
        log.info("This is an info message.");
    }
}

@Value and @Accessors annotations:

The @Value annotation generates an immutable class with final fields for all non-static, non-transient fields, as well as a constructor that initializes these fields. It also generates getter methods for all fields.

The @Accessors annotation configures the naming scheme used for generated methods, such as getters and setters. It has several options, such as fluent, chain, and prefix.

Example:

import lombok.Value;
import lombok.experimental.Accessors;

@Value
@Accessors(fluent = true)
public class Person {
    String firstName;
    String lastName;
    int age;
}

// Usage
Person p = new Person().firstName("John").lastName("Doe").age(30);

@Cleanup annotation:

The @Cleanup annotation automatically closes the declared resource, such as a stream or a file, at the end of the block or when an exception is thrown.

Example:

import lombok.Cleanup;

import java.io.FileOutputStream;
import java.io.IOException;

public class Example {
    public void writeToFile(String text) {
        try {
            @Cleanup FileOutputStream output = new FileOutputStream("example.txt");
            output.write(text.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@SneakyThrows annotation:

The @SneakyThrows annotation is used to avoid declaring checked exceptions in the method signature or handling them in the method body. It converts checked exceptions to unchecked exceptions at compile time.

import lombok.SneakyThrows;

public class Example {
    @SneakyThrows
    public void doSomething() {
        // throws a checked exception
    }
}

@NonNull and @Nullable annotations:

@NonNull: It is used to indicate that a field, parameter, or method return value cannot be null. It generates null-check code for the annotated element at compile-time to prevent NullPointerExceptions. Example:

public void setPerson(@NonNull Person person) {
    this.person = person;
}

@Nullable: It is used to indicate that a field, parameter, or method return value can be null. It can be helpful to make your code more readable by indicating explicitly when null is an acceptable value. Example:

public void setPerson(@Nullable Person person) {
    this.person = person;
}

@Getter(lazy=true) annotation:

This annotation generates a lazily-initialized getter method for a field. The generated method creates and initializes the field on the first call, and returns the initialized value on subsequent calls. Example:

@Getter(lazy=true)
private final List<String> names = new ArrayList<>();

public void addName(String name) {
    names.add(name);
}

// usage
System.out.println(getNames()); // initialize and return the list
addName("John");
addName("Mary");
System.out.println(getNames()); // return the initialized list without re-initializing

@Delegate annotation:

It is used to delegate one or more methods of a field to another object. Example:

public class UserService {
    @Delegate
    private final UserDao userDao = new UserDaoImpl();
}

public interface UserDao {
    void save(User user);
}

public class UserDaoImpl implements UserDao {
    public void save(User user) {
        // implementation
    }
}

// usage
UserService userService = new UserService();
User user = new User("John");
userService.save(user); // delegates to userDao.save(user)

Lombok Extension Libraries:

Overview of Lombok Extension Libraries

Lombok Extension Libraries provide additional functionality beyond the core Lombok library. These libraries are developed by third-party developers and can be easily integrated with your existing Lombok setup. Some popular Lombok Extension Libraries are:

  • Lombok Extension for Spring Framework

  • Lombok Extension for Hibernate and JPA

  • Lombok Extension for Jackson and Gson

Lombok Extension Libraries for Spring Framework

Lombok Extension for Spring Framework provides a set of annotations that make it easier to work with the Spring Framework. Some of the annotations included in this extension library are:

Using these annotations, you can reduce the amount of boilerplate code required to set up Spring Framework components.

Lombok Extension Libraries for Hibernate and JPA

Lombok Extension for Hibernate and JPA provides a set of annotations that make it easier to work with Hibernate and JPA. Some of the annotations included in this extension library are:

Using these annotations, you can reduce the amount of boilerplate code required to set up entities and mappings in Hibernate and JPA.

Lombok Extension Libraries for Jackson and Gson

Lombok Extension for Jackson and Gson provides a set of annotations that make it easier to work with JSON serialization and deserialization using Jackson and Gson. Some of the annotations included in this extension library are:

Using these annotations, you can reduce the amount of boilerplate code required to work with JSON serialization and deserialization in Java applications.

Best Practices and Common Pitfalls:

Best practices:

  1. Use Lombok only when it helps to reduce boilerplate code significantly.

  2. Always include a clear description of the behavior of your class, especially when using Lombok annotations that generate methods, such as @Getter or @Setter.

  3. Use @NoArgsConstructor only for non-abstract classes where it makes sense to have an instance with default values.

  4. Be careful when using @EqualsAndHashCode on classes with collections or circular references. Consider providing an implementation for equals() and hashCode() manually.

  5. Use @Builder when you need to create complex objects with many properties.

  6. Avoid using @Data annotation for large classes or entities with many fields. In such cases, it is better to explicitly define the required methods with @Getter and @Setter annotations.

  7. Use @NonNull and @Nullable to specify whether a parameter or a return value can be null or not.

  8. Use @Slf4j instead of @Log if you're using SLF4J for logging.

Common Pitfalls

  1. Be aware of the side effects of Lombok annotations. For example, @Data generates all methods for you, including equals(), hashCode(), and toString(). Make sure you understand what code is being generated and how it works.

  2. Avoid using Lombok in libraries or frameworks that are shared across different projects, as not everyone may be familiar with Lombok.

  3. Use the latest version of Lombok to avoid potential bugs and issues.

  4. Be careful when using Lombok annotations on interfaces or abstract classes, as the behavior may not always be what you expect.

  5. Lombok annotations may not work correctly with some IDEs or build tools. Make sure to test your code thoroughly before deploying it to production.

Conclusion:

Lombok is a powerful tool for reducing boilerplate code in Java projects. Its annotations help to generate getters, setters, constructors, and other common code patterns automatically. This saves time and reduces the potential for errors in code. However, it is important to use Lombok annotations wisely and with caution. It is essential to understand the annotations and how they affect the generated code. Additionally, it is important to keep in mind the compatibility of Lombok with different IDEs, build tools, and frameworks. When used properly, Lombok can be a great asset to any Java project.

Reference:

  1. Project Lombok website: projectlombok.org

  2. Lombok documentation: projectlombok.org/features/all

I hope this helps, you!!

More such articles:

https://medium.com/techwasti

https://www.youtube.com/channel/UCiTaHm1AYqMS4F4L9zyO7qA

https://www.techwasti.com/

\==========================**=========================

If this article adds any value to you then please clap and comment.

Let’s connect on Stackoverflow, LinkedIn, & Twitter.

Did you find this article valuable?

Support techwasti by becoming a sponsor. Any amount is appreciated!