---
title: "Avoiding Java Boilerplate Code with Project Lombok"
description: "This article demonstrates how you can use Project Lombok library to avoid boilerplate code from your Java projects."
authors:
  - name: "Vladimir Fomene"
    url: "https://auth0.com/blog/authors/vladimir-fomene/"
date: "Jan 30, 2019"
category: "Developers,Tips,Java"
tags: ["java", "lombok", "boilerplate", "spring-boot", "spring", "development"]
url: "https://auth0.com/blog/avoiding-java-boilerplate-code-with-project-lombok/"
---

# Avoiding Java Boilerplate Code with Project Lombok



**TL;DR:** In this article you will learn how to avoid boilerplate code from your Java projects. You will do so by using features of [Project Lombok](https://projectlombok.org/), a wonderful Java library that was created to help developers speed up. You will learn how to use this library's features by using them on small examples. If you want to see the final code created throughout this article, check [the `complete` branch of this GitHub repository](https://github.com/auth0-blog/lombok/tree/complete).

<include src="TweetQuote" quoteText="Learn how to get rid of Java boilerplate code by using Project Lombok."/>

---

## Prerequisites

To follow this article, you will need to have the following tools installed on your system:

* [JDK 8](https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) or any version above.
* Any text editor or IDE of your choice, though I recommend [IntelliJ](https://www.jetbrains.com/idea/download).
* Basic knowledge of the [JUnit testing library](https://junit.org/junit5/).

## Why Use Project Lombok in your Java project

As you might already know from the opening paragraph, Project Lombok is a Java library. I guess the question you are probably asking yourself is, "Why will I be interested in adding this extra dependency to my classpath?". According to the official Project Lombok site, this library will spice up your Java code by automating the creation of **accessor**, **equals**, **hashcode**, **toString** methods, and even help you to implement [the builder pattern](https://en.wikipedia.org/wiki/Builder_pattern) on a class with just one annotation. By automating the creation of these methods on your POJOs (Plain Old Java Objects), Project Lombok will reduce the time spent writing boilerplate code. I will also argue that it will also make your POJOs concise as it will hide the parts that are not that important (from the business point of view) to give more exposure to what makes your POJOs unique.

## How Project Lombok's features work

To use any of the Project Lombok's features, you have to add annotations to your classes. The annotations specify which boilerplate code you want Project Lombok to implement for you.

For example, say you have a class and you do not want to implement its `toString` method manually. All you have to do is add the `@ToString` at the top of your class and, behind the scenes, Project Lombok will use the fields in your class to implement the `toString` method. This process is similar for all Project Lombok's features. With that covered, you are all set to start experimenting with Project Lombok.

## Playing with Project Lombok

For starters, you will need a Java project to use Lombok. To create one, you could follow several different strategies like using [the Spring Initializr website](https://start.spring.io/). However, to make things easier, you can simply open a new terminal and clone a GitHub repository that was created for this article:

```bash
# clone repo
git clone https://github.com/auth0-blog/lombok.git

# move into it
cd lombok
```

Then, you will have to open this project in your favorite IDE. After doing so, the first thing you will need to do is to open the `build.gradle` file and import the Project Lombok's library into your project:

```gradle
//.... rest of file

dependencies {
	// ... don't remove the other dependencies ...
	compileOnly('org.projectlombok:lombok:1.18.4')
	annotationProcessor('org.projectlombok:lombok:1.18.4')
}
```

> **Note:** Your IDE might need a couple of minutes to import the other dependencies and to enable annotation processing if you are planning to run the demos from your IDE.

After adding Lombok into your project, you will need to configure your IDE to generate the boilerplate code for you correctly. The steps to configure this depend on the IDE you are using. Lombok provides some good resources to help you on that matter. On their website, you will find instructions for [IntelliJ](https://projectlombok.org/setup/intellij), [Eclipse](https://projectlombok.org/setup/eclipse), [Netbeans](https://projectlombok.org/setup/netbeans), and more. Make sure you follow the instructions for your IDE before moving on.

### Accessor Annotations

Project Lombok's `@Getter` and `@Setter` annotations, as their name states, automate the generation of _getters_ and _setters_ for non-static fields of your POJOs. For example, if you have a field called `length`, the `@Setter` annotation will create a method called `setLength` to allow developers to change this value. The `@Getter` annotation, on the other hand, will create a `getLength` method which will return the value for whoever is asking.

> **Note**: As Lombok follows conventions, if `length` is a boolean, Lombok will call the getter accessor as `isLength` instead of calling it `getLength`.

There are other interesting Lombok's behaviors that you should know about:

- If you place these annotations on a class field, Project Lombok will automatically generate the accessor methods for you.
- If these annotations are placed on the class, Project Lombok will create accessor methods for all non-static fields of the class. In this case, you can also control the access level of the methods generated by passing `AccessLevel.PROTECTED`, `AccessLevel.PUBLIC`, `AccessLevel.PRIVATE`, `AccessLevel.PACKAGE` as an argument to the accessor annotations.

With the theory covered, now is the time to put all these to practice. Imagine you have an app and you want to create a POJO for your app's users. To do that, you would create a class called `User`. Then, you would add code similar to this on it:

```java
public class User {
    private String username;
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
```

This implementation would work just fine but imagine you would add a dozen more attributes to your class. How would that look? Quite big, wouldn't it? To avoid that, you can use the Project Lombok's annotations you just learned about to _automatically_ generate the getters and setters above.

To see this in action, create the `User` class inside the `com.auth0.lomboktest` package and add the following code to it:

```java
package com.auth0.lomboktest;

import lombok.Getter;
import lombok.Setter;

public class User {

    @Getter @Setter
    private String username;

    @Getter @Setter
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}
```

Do you see how, by using these Lombok's annotations, you have dramatically reduced the amount of code in this class? Both versions presented of the `User` class are equivalent. The difference is that Project Lombok will generate the getters and setters for you because you used Lombok's annotations on the `username` and `password` fields.

To confirm that this is really working, open the `LomboktestApplicationTests` class (you will find it inside the `./src/test/java/com/auth0/lomboktest/` directory) and update it as follows:

```java
package com.auth0.lomboktest;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;

class LomboktestApplicationTests {

  @Test
  void testAccessor() {
    String username = "some-user";
    String password = "some-password";
    User user = new User(username, password);

    assertEquals(username, user.getUsername());
    assertEquals(password, user.getPassword());
  }
}
```

Then, back on the terminal, issue the following command:

```bash
./gradlew test
```

If everything is in place, you should see, among other things, the following output:

```text
> Task :test

com.auth0.lomboktest.LomboktestApplicationTests

  Test testAccessor() PASSED

SUCCESS: Executed 1 tests in 730ms
```

### Builder Annotation

Apart from helping you generate accessor methods, as mentioned, Project Lombok can also help you implement the builder design pattern. As an example, imagine you would create a new class called `Course` that implements the builder pattern. This is what this class would look like:

```java
public class Course {
    @Getter @Setter
    private String courseName;
    @Getter @Setter
    private String courseCode;

    public Course(String courseName, String courseCode){
        this.courseCode = courseCode;
        this.courseName = courseName;
    }

    public static CourseBuilder builder() {
        return new CourseBuilder();
    }

    public static class CourseBuilder {

        private String courseName;

        private String courseCode;

        public CourseBuilder courseName(String courseName){
            this.courseName = courseName;
            return this;
        }

        public CourseBuilder courseCode(String courseCode){
            this.courseCode = courseCode;
            return this;
        }

        public Course build(){
            return new Course(courseName, courseCode);
        }

    }
}
```

As you can see, this class uses the inner `CourseBuilder` class to implement the builder pattern.

Now, to learn about how to replace all this boilerplate code with the help of Lombok, create the `Course` class in the `com.auth0.lomboktest` package and add the following code to it:

```java
package com.auth0.lomboktest;

import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Builder
public class Course {
  @Getter @Setter
  private String courseName;
  @Getter @Setter
  private String courseCode;
}
```

With just the @Builder annotation, Lombok will help you achieve the same result you got on the previous version of the `Course` class. That is, you replaced 20 lines (or so) of boilerplate code by a single annotation. Not to mention that you got this difference in a _very_ simple class with just two fields (`courseName` and `courseCode`). Imagine the difference in a class with a dozen fields... Awesome, isn't it?

Now, to test your builder, update the `LomboktestApplicationTests` class as follows:

```java
package com.auth0.lomboktest;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class LomboktestApplicationTests {

  // ... leave testAccessor untouched ...

  @Test
  void testBuilder() {
    String courseName = "Intro to CS";
    String courseCode = "cs50";
    Course course = Course.builder().courseName(courseName).courseCode(courseCode).build();

    assertEquals(courseName, course.getCourseName());
    assertEquals(courseCode, course.getCourseCode());
  }
}
```

Then, if you run `./gradlew test` in your terminal, you should see that `testBuilder()` passed successfully.

### The Cleanup Annotation

Prepending any resource variable (e.g., `FileInputStream`) with `@Cleanup` will tell Project Lombok to automatically close this resource once it is no longer in use in the current scope.

> **Note:** As of Java 7.0, there is a special `try` statement that automatically does resource management for you.

To demonstrate how to use this annotation, imagine a class where you read from an input file and write to an output file. This class would go more or less like this:

```java
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class VanillaIO {

  public VanillaIO() throws IOException {
    InputStream in = null;

    try {
      in = new FileInputStream("input.txt");
      OutputStream out = null;

      try {
        out = new FileOutputStream("output.txt");
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        out.close();
      }
    } finally {
      in.close();
    }
  }
}
```

With Lombok, you can avoid a lot of the boilerplate code above just by using the `@Cleanup` annotation, as you can see in the following code:

```java
import lombok.Cleanup;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class LombokIO {

  public LombokIO() throws IOException {
    @Cleanup InputStream in = new FileInputStream("input.txt");
    @Cleanup OutputStream out = new FileOutputStream("output.txt");
    byte[] b = new byte[10000];

    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}
```

Notice how this annotation reduces the code to a few lines of code and makes it way cleaner. Cool, isn't it?

### ToString Annotation

Another cool annotation to learn about is the `@ToString` one. Imagine you have a class called `Person` and that you would like to override its `toString` method to something more meaningful. On a normal day, you would have code similar to this:

```java
public class Person {
  private String firstName;
  private String lastName;

  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return "Person(firstName=" + firstName + ", lastName=" + lastName + ")";
  }
}
```

With Lombok, you can simply use the `@ToString` annotation, and that's it:

```java
import lombok.ToString;

@ToString
public class Person {
  private String firstName;
  private String lastName;

  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
}
```

For two field, this might not look like a great deal. However, when you reach a dozen fields, you will see the difference.

To see this in action, create the class above inside the `com.auth0.lomboktest` package, then update the `LomboktestApplicationTests` test class as follows:

```java
class LomboktestApplicationTests {
  // ... testAccessor and testBuilder ...

  @Test
  void testToString() {
    String firstName = "John";
    String lastName = "Doe";
    String expectedResult = "Person(firstName=" + firstName + ", lastName=" + lastName + ")";

    Person person = new Person(firstName, lastName);
    assertEquals(expectedResult, person.toString());
  }
}
```

Now, if you run `./gradlew test`, you will see that Gradle executes three tests successfully.

### The EqualsAndHashCode Annotation

This is, perhaps, one of the coolest features that Lombok introduces. By using the `@EqualsAndHashCode` annotation in your classes, you make Lombok generate the `equals` and `hashcode` methods for you.

Imagine that you have a class called `Lecture` and that [you have to implement the `equals` and `hashcode` to define a custom equality-checking mechanism](https://dzone.com/articles/working-with-hashcode-and-equals-in-java). Without Lombok, you would probably do something like:

```java
import java.util.Objects;

public class Lecture {
  private String lectureName;
  private String lectureCode;

  public Lecture(String lectureName, String lectureCode) {
    this.lectureName = lectureName;
    this.lectureCode = lectureCode;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Lecture that = (Lecture) o;
    return Objects.equals(lectureName, that.lectureName) &&
      Objects.equals(lectureCode, that.lectureCode);
  }

  @Override
  public int hashCode() {
    return Objects.hash(lectureName, lectureCode);
  }
}
```

Not the most beautiful, or readable, code, right? Compare this with the version that Lombok allows:

```java
package com.auth0.lomboktest;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class Lecture {
  private String lectureName;
  private String lectureCode;

  public Lecture(String lectureName, String lectureCode) {
    this.lectureName = lectureName;
    this.lectureCode = lectureCode;
  }
}
```

Yup, that's it! The `equals` and `hashcode` methods disappeared from your code and are now created by Lombok.

To see it in action, update the `LomboktestApplicationTests` class as follows:

```java
class LomboktestApplicationTests {

  // ... other test methods ...

  @Test
  void testEqualsAndHashCode() {
    String lectureName = "Intro to Computer Science";
    String lectureCode = "cs50";

    Lecture l1 = new Lecture(lectureName, lectureCode);
    Lecture l2 = new Lecture(lectureName, lectureCode);

    assertEquals(l1, l2);
  }
}
```

Then, run `./gradlew test`. This should print that four tests were successfully executed.

### The NonNull Annotation

When the `@NonNull` annotation is placed before a method parameter, it means that this method will not accept `null` as an argument. If you pass to it a null object, the method will automatically raise a `NullPointerException` (NPE).

By using this annotation, you avoid having to manually check and to manually raise NPEs. For example, if you had a `Customer` class that didn't accept null for the `name` field, instead of doing this:

```java
public class Customer {
  private String name;
  private String phone;

  public Customer(String name, String phone) {
    if (name == null) {
      throw new NullPointerException("Customer name required.");
    }

    this.name = name;
    this.phone = phone;
  }
}
```

You would do this:

```java
import lombok.NonNull;

public class Customer {
  private String name;
  private String phone;

  public Customer(@NonNull String name, String phone) {
    this.name = name;
    this.phone = phone;
  }
}
```

Want to see this in action? Just create the above class inside the `lomboktest` package then update the `LomboktestApplicationTests` method as follows:

```java
// ... package name and other import statements ...

import static org.junit.jupiter.api.Assertions.assertThrows;

class LomboktestApplicationTests {
  // ... other test methods ...

  @Test
  void testNullPointerExceptions() {
    Customer okCustomer = new Customer("Someone", null);
    assertThrows(NullPointerException.class, ()->{new Customer(null, null);});
  }
}
```

Then, after you run `./gradlew test`, you will see that five tests were executed successfully.

### The Constructor Annotations

In this section, you will learn about two annotations: `@NoArgsConstructor` and `@AllArgsConstructor`. As their name states, the first annotation creates an empty constructor (no arguments on it) and the second one creates a constructor that contains all the fields on the class.

You probably already know the drill, right? So, instead of seeing how you would do on a vanilla-Java class, you can skip and create a class called `Product` inside the `com.auth0.lomboktest` package. Then, add the following code to this class:

```java
package com.auth0.lomboktest;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Product {
  private String title;
  private String description;
  private boolean available;
  private BigDecimal price;
  private BigDecimal weight;
}
```

In this case, just by adding `@NoArgsConstructor` and `@AllArgsConstructor`, you make Lombok create an empty constructor and also a constructor that get values for all the five fields defined (`title`, `description`, `available`, `price`, and `weight`).

To test these annotations, update the `LomboktestApplicationTests` class as follows:

```java
// ... package name and other import statements ...

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.math.BigDecimal;

class LomboktestApplicationTests {

  // ... other test methods ...

  @Test
  void testConstructors() {
    Product unknown = new Product();
    assertNull(unknown.getTitle());
    assertNull(unknown.getDescription());
    assertFalse(unknown.isAvailable());
    assertNull(unknown.getPrice());
    assertNull(unknown.getWeight());

    String title = "Pizza";
    String description = "Delicious";
    boolean available = true;
    BigDecimal price = BigDecimal.valueOf(15);
    BigDecimal weight = BigDecimal.valueOf(0.9);

    Product pizza = new Product(title, description, available, price, weight);
    assertEquals(title, pizza.getTitle());
    assertEquals(description, pizza.getDescription());
    assertTrue(pizza.isAvailable());
    assertEquals(price, pizza.getPrice());
    assertEquals(weight, pizza.getWeight());
  }
}
```

Then, run `./gradlew test`. If everything is in place, you will see that six tests were executed successfully.

Lombok also provides another annotation called `@RequiredArgsConstructor`. This annotation generates a constructor with one parameter for each field that requires special handling. All non-initialized final fields get a parameter, as well as any fields that are marked as @NonNull that aren't initialized where they are declared. [Take a look here to learn more about it](https://projectlombok.org/features/constructor).

### The Data Annotation

The last annotation that you will learn about in this article is the `@Data` one. This annotation is a handy combination of the  `@ToString`, `@EqualsAndHashCode`, `@Getter`, `@Setter` and `@RequiredArgsConstructor` annotations. That is, by using this annotation, you make Lombok:

- override the `toString` method;
- define the `equals` and `hashcode` methods;
- create getters and setters for your class' fields;
- define a constructor for all non-initialized and non-nullable fields;

To see this annotation in action, create a class called `Magic` inside the `com.auth0.lomboktest` package with the following code:

```java
package com.auth0.lomboktest;

import lombok.Data;
import lombok.NonNull;

@Data
public class Magic {
  private @NonNull String title;
  private @NonNull Integer grade;
  private boolean works = true;
  private String description;
}
```

Then, update the `LomboktestApplicationTests` class as follows:

```java
class LomboktestApplicationTests {

  // ... other test methods ...

  @Test
  void testData() {
    String title = "Lombok";
    Integer grade = 10;

    Magic m1 = new Magic(title, grade);
    Magic m2 = new Magic(title, grade);

    assertEquals(m1, m2);
    assertEquals(title, m1.getTitle());
    assertEquals(grade, m2.getGrade());
    assertTrue(m1.isWorks());
  }
}
```

Running `./gradlew test` now should output that seven tests were executed successfully. This proves that `@Data` is capable of creating comparable objects (`@EqualsAndHashCode`), classes that contain constructors with the required fields (`@RequiredArgsConstructor`), and that it also generates the getters and setters for you. Cool, huh?

<include src="TweetQuote" quoteText="Lombok helps us to replace a looot of Java boilerplate code by just a few annotations."/>

## Conclusion

In this article, you learned how to use Project Lombok's annotations to remove boilerplate code from your project. In the sections above you learned about cool features provided by Lombok like `@Data`, `@EqualsAndHashCode`, constructor annotations, `@Builder`, and a few others.

On their own, are these features useful enough to make you use Lombok on your next project? Even if they are, be aware, Lombok includes a few other features that might be handy. [Check this resource for a complete list of Lombok's features](https://projectlombok.org/features/all).
