---
title: "A Complete Guide to Lombok"
description: "Let’s see everything you should know to start using Project Lombok. We will have a look at how to integrate it into your IDE and use it to avoid boilerplate code."
authors:
  - name: "Antonello Zanini"
    url: "https://auth0.com/blog/authors/antonello-zanini/"
date: "Jul 29, 2021"
category: "Developers,Deep Dive,JAVA"
tags: ["java", "lombok", "library"]
url: "https://auth0.com/blog/a-complete-guide-to-lombok/"
---

# A Complete Guide to Lombok

Java is a great but verbose language. You may be ending up writing many lines of code even to achieve the most common goals. Plus, it definitely involves repetitive code, like getters and setters. This leads to a huge amount of boilerplate and avoidable code. Not only does this add nothing to the business logic of your application, but writing it is an unnecessarily boring and time-consuming process. This is why you should start employing tools and libraries to make you more productive by avoiding this. That’s where Lombok comes into play!

This Java library provides you with several annotations aimed at avoiding writing Java code known to be repetitive and/or boilerplate. Project Lombok works by plugging into your build process. Then, it will auto-generate the Java bytecode into your *.class* files required to implement the desired behavior, based on the annotations you used. Thus, each annotation offered by Project Lombok allows you to skip writing methods and logic you would like to avoid, like constructors, equals, and hash code functions. This will save you a lot of time and let you focus on the business logic of your project. Plus, you will be able to keep your codebase smaller, cleaner, and easier to be read and maintained.

First, we will see what Project Lombok is and how it works. Then, we will study the most common and relevant Lombok’s annotations, understanding what the most important ones are, where, and how to use them. Next, it will be time to see how to integrate it in your IDE ([Integrated Development Environment](https://en.wikipedia.org/wiki/Integrated_development_environment)) and why you should not be afraid of using it.

## Prerequisites

This is the list of all the prerequisites to replicate the examples that will be shown next:

* Java >= 1.8
* Gradle >= 4.x or Maven 3.6.x
* Project Lombok >= 1.18.20

## What is Lombok

[Project Lombok](https://projectlombok.org/) (from now on, *Lombok*) is an annotation-based Java library that allows you to reduce boilerplate code. Lombok offers various annotations aimed at replacing Java code that is well known for being boilerplate, repetitive, or tedious to write. For example, by using Lombok, you can avoid writing constructors with no arguments, `toString()`, `equals()`, and `hashCode()` methods by simply adding a few annotations. The magic happens during the compile-time when the library injects the bytecode representing the desired and boilerplate code into your *.class* files. Plus, as we will see, the library can be plugged into your IDE, letting you have the same experience as if you had written all the boilerplate code yourself.

You can easily install Lombok by adding [`lombok`](https://mvnrepository.com/artifact/org.projectlombok/lombok/1.18.20) to your dependencies.
If you are a [Gradle user](https://projectlombok.org/setup/gradle), add these two lines to the dependencies section of your `build.gradle` file:

```gradle
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
```

While if you are a [Maven user](https://projectlombok.org/setup/maven), add the following dependency to your `pom.xml` file:

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

Plus, add the Lombok dependency to the [`maven-compiler-plugin`](https://maven.apache.org/plugins/maven-compiler-plugin/) configuration section as follows :

```xml
<build>
      <plugins>      
            
            <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-compiler-plugin</artifactId>
                  <version>3.5.1</version>
                  <configuration>
                        <source>11</source> <!-- depending on your project -->
                        <target>11</target> <!-- depending on your project -->
                        <annotationProcessorPaths>
                              <path>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                    <version>1.18.20</version>
                              </path>                              
                        </annotationProcessorPaths>
                  </configuration>
            </plugin>
            
            <!-- ... -->  
            
      </plugins>
</build>
```
Now, you have all you need to start using Lombok.

## Most Common Lombok Annotations

Here you can find the most common and important Lombok annotations. Each of them will be explained and then seen in use compared to the equivalent Java vanilla translation. To see examples and get more support, click on each annotation and visit its page on the [Lombok official documentation](https://projectlombok.org/features/all).

### [`@Getter`](https://projectlombok.org/features/GetterSetter), [`@Setter`](https://projectlombok.org/features/GetterSetter)

When a field is annotated with `@Getter` and/or `@Setter`, Lombok will automatically generate the default getter and/or setter, respectively. The default implementation for getters simply takes care of returning the annotated field. Similarly, the default implementation for setters takes one parameter of the same type as the annotated field and simply sets it with the received value. When a field called `value` is annotated with both `@Getter` and `@Setter`, Lombok will define a `getValue()` (or `isValue()` if the field is `boolean`), and a `setValue()` method. The generated getter/setter method will be `public`, unless a particular `AccessLevel` is specified. The allowed `AccessLevel` values are `PUBLIC`, `PROTECTED`, `PACKAGE`, and `PRIVATE`. Please, note that you can also annotate the entire class. In this case, this logic will be applied to each field.

#### With Lombok
```java
@Getter
@Setter
public class Author {
    private int id;
    private String name;
    @Setter(AccessLevel.PROTECTED)
    private String surname;
}
```

#### Java Vanilla
```java
public class User {
    private int id;
    private String name;
    private String surname;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getSurname() {
        return surname;
    }

    protected void setSurname(String surname) {
        this.surname = surname;
    }
}
 ```

### [`@NoArgsConstructor`](https://projectlombok.org/features/constructor), [`@RequiredArgsConstructor`](https://projectlombok.org/features/constructor), [`@AllArgsConstructor`](https://projectlombok.org/features/constructor)

When a class is annotated with `@NoArgsConstructor`, Lombok will take care of automatically generating a constructor with no parameters. Likewise, when annotated with `@AllArgsConstructor`, a constructor with one parameter for each field in your class will be generated. Similarly, `@RequiredArgsConstructor` leads to a constructor with a parameter for each field requiring special handling. In particular, this involves non-initialized `final` fields, as well as any fields marked as `@NonNull` that are not initialized where declared. Please, do not forget that static fields will be ignored by these annotations.

#### With Lombok
```java
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
public class Author {
    private int id;
    private String name;
    private String surname;
    private final String birthPlace;
}
```

#### Java Vanilla
```java
public class Author {
    private int id;
    private String name;
    private String surname;
    private final String birthPlace;

    // @NoArgsConstructor
    public Author() {}

    // @AllArgsConstructor
    public Author(int id, String name, String surname, String birthPlace) {
      this.id = id
      this.name = name
      this.surname = surname
      this.birthPlace = birthPlace
    }

    // @RequiredArgsConstructor
    public Author(String birthPlace) {
      this.birthPlace = birthPlace
    }
}
 ```

### [`@ToString`](https://projectlombok.org/features/ToString)

When a class is annotated with `@ToString`, Lombok will take care of generating a proper implementation of the `toString()` method. By default, a String containing the class name, followed by each field's value separated by a comma, will be returned. By setting the `includeFieldNames` parameter to *true*, the name of each field will be placed before its value. By default, all non-static fields will be considered when generating the `toString()` method. Annotate a field with `@ToString.Exclude` to make Lombok ignore it. Alternatively, you can specify which fields you wish to be taken into account by using `@ToString(onlyExplicitlyIncluded = true)`. Then, mark each field you want to include with `@ToString.Include`.

#### With Lombok
```java
@ToString(includeFieldNames=true)
public class Author {
    private int id;
    private String name;
    private String surname;
}
```

#### Java Vanilla
```java
public class Author {
    private int id;
    private String name;
    private String surname;

    @Override 
    public String toString() {
      return "Author(id=" + this.id + ", name=" + this.name + ", surnname=" + this.surname + ")";
  }
}
```

### [`@EqualsAndHashCode`](https://projectlombok.org/features/EqualsAndHashCode)

Annotate a class with `@EqualsAndHashCode`, and Lombok will automatically implement the `equals()` and `hashCode()` methods for you. By default, all non-static, non-transient fields will be taken into account. You can modify which fields are used by annotating them with `@EqualsAndHashCode.Include` or `@EqualsAndHashCode.Exclude`. Alternatively, you can annotate your class with `@EqualsAndHashCode(onlyExplicitlyIncluded = true)` and then specify exactly which fields or methods you want to be used by marking them with `@EqualsAndHashCode.Include`. Please, note that the [`equals()`](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)) and [`hashCode()`](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode()) methods will be generated by Lombok without breaking the contract between them. Follow the link on the two methods to the official Java documentation to learn more about the contracts that `equals()` and `hashCode()` implementations should fulfill.
 
#### With Lombok
```java
@Getter
@Setter
@EqualsAndHashCode
public class Author {
    private int id;
    private String name;
    private String surname;
}
```

#### Java Vanilla
```java
public class Author {
    
    // gettes and setters ...

    @Override 
    public int hashCode() {
       final int PRIME = 31;
       int result = 1;
       result = prime * result + id;
       result = prime * result + ((name == null) ? 0 : name.hashCode());
       result = prime * result + ((surname == null) ? 0 : surname.hashCode());
       return result;
    }

    @Override 
    public boolean equals(Object o) {
       if (o == this) return true;
       if (!(o instanceof Author)) return false;
       Author other = (Author) o;
       if (!other.canEqual((Object)this)) return false;
       if (this.getId() == null ? other.getId() != null : !this.getId().equals(other.getId())) return false;
       if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
       if (this.getSurname() == null ? other.getSurname() != null : !this.getSurname().equals(other.getSurname())) return false;
       return true;
    }
}
```

### [`@NonNull`](https://projectlombok.org/features/NonNull)

You can annotate with `@NonNull` a record component, a parameter of a method, or an entire constructor. This way, Lombok will generate null-check statements for you accordingly.

#### With Lombok
```java
public class Author {
    private int id;
    private String name;
    private String surname;

    public Author(
      @NonNull int id,
      @NonNull String name,
      String surname
    ) {
      this.id = id;
      this.name = name;
      this.surname = surname; 
  }
}
```

#### Java Vanilla
```java
public class Author {
    private int id;
    private String name;
    private String surname;

    public Author(
      int id,
      String name,
      String surname
    ) {
        if (id == null) {
          throw new NullPointerException("id is marked @NonNull but is null");
        }
        this.id = id;
        if (name == null) {
          throw new NullPointerException("name is marked @NonNull but is null");
        }
        this.name = name;
        this.surname = surname; 
  }
}
 ```

### [`@Data`](https://projectlombok.org/features/Data)

`@Data` is a shortcut annotation that combines the features of [`@ToString`](https://projectlombok.org/features/ToString), [`@EqualsAndHashCode`](https://projectlombok.org/features/EqualsAndHashCode), [`@Getter`](https://projectlombok.org/features/GetterSetter) [`@Setter`](https://projectlombok.org/features/GetterSetter), and [`@RequiredArgsConstructor`](https://projectlombok.org/features/constructor) together. So, `@Data` generates all the boilerplate involved in POJOs ([Plain Old Java Objects](https://en.wikipedia.org/wiki/Plain_old_Java_object)). This means, in particular, getters for all fields, setters for all non-final fields, proper `toString`, `equals`, and `hashCode` implementations involving every field of the class, and a constructor for all final fields.

#### With Lombok
```java
@Data
public class Author {
    private final int id;
    private String name;
    private String surname;
}
```

#### Java Vanilla
```java
public class Author {
    private final int id;
    private String name;
    private String surname;

    public Author(int id) {
        this.id = id;
    }    

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

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

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    @Override 
    public int hashCode() {
       final int PRIME = 31;
       int result = 1;
       result = prime * result + getId();
       result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
       result = prime * result + ((getSurname() == null) ? 0 : getSurname().hashCode());
       return result;
    }

    @Override 
    public boolean equals(Object o) {
       if (o == this) return true;
       if (!(o instanceof Author)) return false;
       Author other = (Author) o;
       if (!other.canEqual((Object)this)) return false;
       if (this.getId() == null ? other.getId() != null : !this.getId().equals(other.getId())) return false;
       if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
       if (this.getSurname() == null ? other.getSurname() != null : !this.getSurname().equals(other.getSurname())) return false;
       return true;
    }
}
``` 

### [`@Value`](https://projectlombok.org/features/Value)

`@Value` is the immutable variant of [`@Data`](https://projectlombok.org/features/Data). This means that all fields are made `private` and `final` by Lombok by default. Plus, setters will not be generated, and the class itself will be marked as `final`. This way, the class will not be inheritable. Just like what happens with `@Data`, `toString()`, `equals()` and `hashCode()` implementations are also created.

#### With Lombok
```java
@Data
public class Author {
    int id;
    String name;
    String surname;
}
```

#### Java Vanilla
```java
public final class Author {
    private final int id;
    private final String name;
    private final String surname;

    public Author(int id, String name, String surname) {
      this.id = id
      this.name = name
      this.surname = surname
    }  

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    @Override 
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = prime * result + getId();
        result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
        result = prime * result + ((getSurname() == null) ? 0 : getSurname().hashCode());
        return result;
    }

    @Override 
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof Author)) return false;
        Author other = (Author) o;
        if (!other.canEqual((Object)this)) return false;
        if (this.getId() == null ? other.getId() != null : !this.getId().equals(other.getId())) return false;
        if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
        if (this.getSurname() == null ? other.getSurname() != null : !this.getSurname().equals(other.getSurname())) return false;
        return true;
    }
}
```
## Advanced Lombok Annotations

Here you can find the most complex Lombok annotations. Each of them will be explained and then seen in use compared to the equivalent Java vanilla translation. To see examples and get more support, click on each annotation and visit its page on the [Lombok official documentation](https://projectlombok.org/features/all).

### [`@Cleanup`](https://projectlombok.org/features/Cleanup)

`@Cleanup` can be used to ensure a given resource is automatically cleaned up before leaving the current scope. By default, the cleanup method of the annotated resource is assumed to be `close()`, but you can specify the name of the desired method to be called instead. Note that this annotation works by harnessing the [try-with-resources statement](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html).

#### With Lombok
```java
public class CleanupDemo {
  public static void main(String[] args) throws IOException {
    @Cleanup 
    InputStream input = new FileInputStream(args[0]);

    @Cleanup 
    OutputStream output = new FileOutputStream(args[1]);

    byte[] b = new byte[10000];

    while (true) {
      int r = input.read(b);

      if (r == -1) 
        break;

      output.write(b, 0, r);
    }
  }
}
```

#### Java Vanilla
```java
public class CleanupDemo {
  public static void main(String[] args) throws IOException {
    try (OutputStream output = new FileOutputStream(args[1])) {
      try (InputStream input = new FileInputStream(args[0])) {
        byte[] b = new byte[10000];

        while (true) {
          int r = input.read(b);

          if (r == -1) 
            break;

          output.write(b, 0, r);
        }
      }       
    } 
  }
}
```

### [`@Synchronized`](https://projectlombok.org/features/Synchronized)

`@Synchronized` allows you to achieve something similar to the [`synchronized`](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) keyword, but locking on different objects. The keyword locks on `this`, while the annotation locks on a special private field named `$lock`. If this field does not exist, it will be created by Lombok. This is the default behavior, but you can also specify lock objects yourself. When dealing with `static` methods, the annotation will lock on a static field named `$LOCK`. Please, consider that just like `synchronized`, the annotation can only be used on static and instance methods. 

#### With Lombok
```java
public class SynchronizedDemo {
  private final Object objectToLock = new Object();
  
  @Synchronized
  public static void sayHello() {
    System.out.println("Hello!");
  }
  
  @Synchronized
  public int getOne() {
    return 1;
  }
  
  @Synchronized("objectToLock")
  public void printObject() {
    System.out.println(objectToLock);
  }
}
```

#### Java Vanilla
```java
public class SynchronizedDemo {
  private static final Object $LOCK = new Object[0];
  private final Object $lock = new Object[0];
  private final Object readLock = new Object();
  
  public static void sayHello() {
    synchronized($LOCK) {
      System.out.println("Hello");
    }
  }
  
  public int getOne() {
    synchronized($lock) {
      return 1;
    }
  }
  
  public void printObject() {
    synchronized(readLock) {
      System.out.println(objectToLock);
    }
  }
}
 ```

### [`@SneakyThrows`](https://projectlombok.org/features/SneakyThrows)

`@SneakyThrows` can be used to sneakily throw checked exceptions without actually declaring them in your method's `throws` clause, as you normally would. So, this annotation allows you to avoid the required `try-catch` blocks completely by handling all the checked exceptions quietly. Lombok will not ignore, wrap, replace, or modify the thrown checked exception. On the contrary, it will mislead the compiler. In fact, at the JVM ([Java Virtual Machine](https://en.wikipedia.org/wiki/Java_virtual_machine)) class file level, all exceptions can be thrown regardless of the `throws` clause of your methods, which is why this works. This annotation can be dangerous and should be used carefully. This is why you should read [this](https://projectlombok.org/features/SneakyThrows) page from the Lombok official documentation to learn more about when and how to use it.

### [`@Builder`](https://projectlombok.org/features/Builder)

You may need to develop a builder object allowing you to create objects by following a step-by-step construction pattern, such as `Author.builder().id("1").name("Maria").surname("Williams").build();`. This is particularly useful when dealing with large classes with several fields. Instead of using a constructor with many parameters, you can use this more readable approach.
By using the `@Builder` annotation, you let Lombok generate the builders for you. By annotating a class with `@Builder`, Lombok will produce a class implementing the aforementioned builder pattern. For example, by annotating the `Author` class, an `AuthorBuilder` class will be automatically generated. Since the behavior of your builder may be complex or highly-tailored, Lombok offers many parameters to achieve the desired result. You can find out them all [here](https://projectlombok.org/features/Builder).

### [`@Log`](https://projectlombok.org/features/log)

The majority of loggers require you to set up a logger instance in every class where you want to log. This definitely involves boilerplate code. By annotating a class with `@Log`, Lombok will automatically add a static final `log` field, initialized as required by your logging library. This is why Lombok provides developers with an annotation per each of the most popular logging frameworks. You can find the entire list [here](https://projectlombok.org/features/log).

## The Lombok Plugin

The most popular and widely used IDEs come with an official Lombok plugin designed to help developers use Lombok. In particular, it supports you by offering shortcuts to the most common Lombok annotation. Plus, it suggests to you the annotations you may require or be looking for based on where you clicked. At the time of writing [IntelliJ IDEA](https://projectlombok.org/setup/intellij), [Eclipse, Spring Tool Suite, (Red Hat) JBoss Developer Studio, MyEclipse](https://projectlombok.org/setup/eclipse), [Microsoft Visual Studio Code](https://projectlombok.org/setup/vscode), and [Netbeans](https://projectlombok.org/setup/netbeans) are officially supported. Follow the link related to your IDE to get support on how to install it.
Visit the [Lombok](https://projectlombok.org/) website for the complete list of all supported IDEs.

## Is Using Lombok A Risk?

You may be concerned about spreading Lombok annotations throughout your codebase. In fact, what would happen if you decided to avoid using it? You might be finding yourself stuck. Well, this is not a real problem because Lombok comes with a *delombok* tool. 
As stated [in the official documentation](https://projectlombok.org/features/delombok), although not covering all possible IDEs and cases, it makes the process of freeing your code from Lombok easier. What this tool does is auto-generate Java source code containing the same features contained in the bytecode Lombok would have injected. This way, your Lombok annotated codebase will be simply replaced with a standard, non-Lombok Java one. 
As a result, your entire project will no longer depend on Lombok. So, to answer the original question, no, not at all. Using Lombok does not represent a risk for the future or your project.

## Conclusion

In this article, we looked at how to use Project Lombok, a Java library that automatically plugs into your editor and builds tools, to avoid writing boilerplate, boring, and repetitive code Java is well known for. As shown, this is an easy way to make you a more productive developer and do not waste your time on cumbersome activities. By starting to take advantage of its most relevant annotations, you can avoid writing thousand of lines of code with no real value from the business logic point of view of your project. Plus, there is always the possibility to make your project no longer depend on Project Lombok easily. So, it using it does not represent a risk of finding yourself locked in. In conclusion, every Java developer should use Project Lombok, and explaining everything you need to start using it is what this article was aimed at.

Thanks for reading! I hope that you found this article helpful. Feel free to reach out to me with any questions, comments, or suggestions.