DEV Community

Jitendra Singh Bisht
Jitendra Singh Bisht

Posted on • Originally published at jsblogs.github.io on

4 4

Introduction to Lombok (Speeding-up Java development)

Hi Guys, today I am going to talk about Project Lombok. This blog post is divided into 3 parts:

  1. Introduction
  2. Setup (Using IntelliJ idea)
  3. Lombok Annotations

1. Introduction

Lombok is java library which helps in reducing boilerplate code. So that you are more focused on your actual code. e.g. A Simple POJO class consists of properties, getters/setter (, Constructors), so here Lombok will help you in auto-generation of Getter/Setters (and Constructors) by just adding an annotation.

2. Setup

  1. Check your Idea build number. Go to Help -> About About

  2. Download Lombok plugin for Idea IntelliJ https://plugins.jetbrains.com/plugin/6317 as per your build number.

  3. Goto File -> Settings -> Type Plugins in search text box at top left. Plugin Settings

  4. Now click Install plugin from disk. button and select the downloaded Lombok Plugin.

  5. You are done now

In case you are using eclipse please refer to This Blog Post.

3. Lombok Annotations

Lombok has many different types of annotations for different tasks. You can view the full list of annotations here. In this blog, we will discuss the following annotations.

  1. @Getter/@setter
  2. @ToString and @EqualsAndHashCode
  3. @NonNull
  4. @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
  5. @data
  6. @Value
  7. @builder
  8. @Cleanup

At first, you need to add Lombok dependency in your classpath. If you are using maven then add bellow dependency in your pom.xml.

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.10</version>
    </dependency>
</dependencies>

Gradle user will add below dependency in build.gradle file.

dependencies {
compile("org.projectlombok:lombok:1.16.10")
}

1. @Getter/@setter

Everyone is familiar with Getters/Setters in normal POJO. Generating getter/setter is not a big task, these days IDE is smart enough and it can generate those for you, but it increases your LOC and managing them could be a bit cumbersome. Lombok helps you in generating getter/setter by just adding @Getter and @Setter. By default generated methods type is public but you can change the type by overriding value property of @Getter/@setter which takes AccessLevel enum type. Available AccessLevel enum values are [PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE, NONE]. If you set the value to AccessLevel.NONE then no getter/setter will be generated.

package samples.lombok;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jitendra Singh.
*/
public class GetterAndSetterLombok {
@Getter
@Setter
private String name;
@Getter
@Setter(AccessLevel.PROTECTED)
private int age;
@Getter
@Setter(AccessLevel.NONE)
private boolean isMale;
}

You can add these annotations on Class level too. It will generate getters for all fields and setters for all non-final and non-static fields.

package samples.lombok;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jitendra Singh.
*/
@Getter
@Setter
public class GetterAndSetterLombokClassLevel {
private String name;
@Setter(AccessLevel.PROTECTED)
private int age;
@Setter(AccessLevel.NONE)
private boolean isMale;
}

Above code is equvalant to

package samples.lombok;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* @author Jitendra Singh.
*/
public class GetterAndSetterNormal {
private String name;
private int age;
private boolean isMale;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
protected void setAge(int age) {
this.age = age;
}
public boolean isMale() {
return isMale;
}
}

Note: @Setter will not work on final fields.

2. @ToString and @EqualsAndHashCode

@ToString and @EqualsAndHashCode generates toString(), equals(Object object) and hashCode() in our pojo. By default @ToString includes Classname and all non-static fields. You can specify fields in of property of @ToString. You can also exclude fields by exclude property.

By default @EqualsAndHashCode include non-static and non-transient fields. You can include or exclude fields by providing in of and exclude property (Same as @ToString). It has extra property called callSuper which invokes superclass’s implementation of hashCode() and equals(). By default, it doesn’t invoke superclass methods. You can override it by setting its value to true.

package samples.lombok;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
/**
* @author Jitendra Singh.
*/
@ToString
@EqualsAndHashCode
public class ToStringAndEqualsAndHashCode {
private String name;
private int age;
private transient String tr = "Transient Field";
private final String CONSTANT = "CONSTANT";
}

3. @NonNull

This annotation will generate null-check for any field. It can be used with Constructor args, fields or method args.

package samples.lombok;
import lombok.NonNull;
import lombok.Setter;
/**
* @author Jitendra Singh.
*/
public class NonNullCheck {
@NonNull @Setter
private String name;
public NonNullCheck(@NonNull String city) {
}
}

Above code is equivalent to

package samples.lombok;
import lombok.NonNull;
/**
* @author Jitendra Singh.
*/
public class NonNullCheckNormal {
private String name;
public void setName(String name) {
if(name == null)
throw new NullPointerException("name");
this.name = name;
}
public NonNullCheckNormal(String city) {
if(city == null)
throw new NullPointerException("city");
}
}

4. @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

@NoArgsConstructor will generate default constructor. If your class contains final fields, then a compilation error will be generated. So if you want to generate default constructor with default values for final fields set force=true @NoArgsConstructor(force = true).

package samples.lombok;
import lombok.ToString;
/**
* @author Jitendra Singh.
*/
@ToString
@lombok.NoArgsConstructor(force = true)
public class NoArgsConstructor {
private final String name;
private int age;
}

Above code is equvalant to

package samples.lombok;
/**
* @author Jitendra Singh.
*/
public class NoArgsConstructorNormal {
private final String name;
private int age;
public NoArgsConstructorNormal() {
this.name = null;
}
@Override
public String toString() {
return "NoArgsConstructorNormal(" +
"name=" + name +
", age=" + age +
')';
}
}

@RequiredArgsConstructor will generate constructor, if your class contains final fields or any field marked with @lombok.NotNull then it’ll generate parameterized constructor and those fields will be added in constructor args and a null check will be added in constructor.

package samples.lombok;
import lombok.ToString;
/**
* @author Jitendra Singh.
*/
@lombok.RequiredArgsConstructor
@ToString
public class RequiredArgsConstructor {
private final String name;
private int age;
@lombok.NonNull
private String city;
}

Above code is equvalant to

package samples.lombok;
/**
* @author Jitendra Singh.
*/
public class RequiredArgsConstructorNormal {
private final String name;
private int age;
private String city;
public RequiredArgsConstructorNormal(String name, String city) {
if(city == null) {
throw new NullPointerException("city");
}
this.city = city;
this.name = name;
}
@Override
public String toString() {
return "RequiredArgsConstructorNormal(" +
"name=" + name +
", age=" + age +
", city=" + city +
')';
}
}

@AllArgsConstructor will generate parameterized constructor with all fields as constructor args.

package samples.lombok;
import lombok.NonNull;
/**
* @author Jitendra Singh.
*/
@lombok.AllArgsConstructor
public class AllArgsConstructor {
private final String name;
@NonNull
private String city;
private int age;
}

Above code is equvalant to

package samples.lombok;
/**
* @author Jitendra Singh.
*/
public class AllArgsConstructorNormal {
private final String name;
private String city;
private int age;
public AllArgsConstructorNormal(String name, String city, int age) {
if(city == null) {
throw new NullPointerException("city");
}
this.city = city;
this.name = name;
this.age = age;
}
}

Note: If you want to generate static factory method with private constructor then set staticName property of @xxxConstructor.

package samples.lombok;
/**
* @author Jitendra Singh.
*/
@lombok.AllArgsConstructor(staticName = "getInstance")
public class ConstructorWithFactoryMethod {
private String name;
private int age;
}

Above code is equivalent to

package samples.lombok;
/**
* @author Jitendra Singh.
*/
public class ConstructorWithFactoryMethodNormal {
private String name;
private int age;
private ConstructorWithFactoryMethodNormal(String name, int age) {
}
public static ConstructorWithFactoryMethodNormal getInstance(String name, int age) {
return new ConstructorWithFactoryMethodNormal(name, age);
}
}

5. @data

@Data annotation can only be used with Class and it covers below annotations:

  • @Getter
  • @setter
  • @RequiredArgsConstructor
  • @ToString
  • @EqualsAndHashCode
  • @Value
    package samples.lombok;
    import lombok.Data;
    /**
    * @author Jitendra Singh.
    */
    @Data
    public class DataLombok {
    private final String name;
    private int age;
    }
    view raw DataLombok.java hosted with ❤ by GitHub
    Above code is equvalant to
    package samples.lombok;
    /**
    * @author Jitendra Singh.
    */
    public class DataLombokNormal {
    private final String name;
    private int age;
    public DataLombokNormal(String name) {
    this.name = name;
    }
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    this.age = age;
    }
    public String getName() {
    return name;
    }
    @Override
    public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    DataLombokNormal that = (DataLombokNormal) o;
    if (age != that.age) return false;
    return name.equals(that.name);
    }
    @Override
    public int hashCode() {
    int result = name.hashCode();
    result = 31 * result + age;
    return result;
    }
    @Override
    public String toString() {
    return "DataLombokNormal(" +
    "name=" + name +
    ", age=" + age +
    ')';
    }
    }

6. @Value

@Value is used to create Immutable POJO. By default class and all fields made final and no setters will be generated. Just like @Data it also generates toString(), hashCode() and equals(). If you don’t want to make a field final then mark it with @NonFinal.

package samples.lombok;
import lombok.Value;
import lombok.experimental.NonFinal;
/**
* @author Jitendra Singh.
*/
@Value
public class ValueLombok {
String name;
int age;
@NonFinal String city;
}
Above code is equivalent to
package samples.lombok;
/**
* @author Jitendra Singh.
*/
public final class ValueLombokNormal {
private final String name;
private final int age;
private String city;
public ValueLombokNormal(String name, int age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getCity() {
return city;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ValueLombokNormal that = (ValueLombokNormal) o;
if (age != that.age) return false;
if (!name.equals(that.name)) return false;
return city.equals(that.city);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + age;
result = 31 * result + city.hashCode();
return result;
}
@Override
public String toString() {
return "ValueLombokNormal(" +
"name=" + name +
", age=" + age +
", city=" + city +
')';
}
}

7. @builder

@Builder is used to generate builder API pattern. It generates an inner class called <YourClassName>Builder which expose builder pattern-based setters. @Singular is used with @Builder and only valid with java.util.List types. This annotation will add to adder methods one for single elements and another for the complete collection.

package samples.lombok;
import lombok.Builder;
import lombok.Singular;
import java.util.List;
/**
* @author Jitendra Singh.
*/
@Builder
public class BuilderLombok {
private String name;
private int age;
@Singular private List<String> addresses;
}
Above code is equivalent to
package samples.lombok;
import lombok.Builder;
import lombok.Singular;
import java.util.ArrayList;
import java.util.List;
/**
* @author Jitendra Singh.
*/
@Builder
public class BuilderLombokNormal {
private String name;
private int age;
@Singular private List<String> addresses;
private BuilderLombokNormal(String name, int age, List<String> addresses) {
this.name = name;
this.age = age;
this.addresses = addresses;
}
public static class BuilderLombokNormalBuilder {
private String name;
private int age;
private List<String> addresses;
public BuilderLombokNormalBuilder name(String name) {
this.name = name;
return this;
}
public BuilderLombokNormalBuilder age(int age) {
this.age = age;
return this;
}
public BuilderLombokNormalBuilder addresses(String address) {
if(addresses == null) {
addresses = new ArrayList<>();
}
this.addresses.add(address);
return this;
}
public BuilderLombokNormalBuilder addresses(List<String> address) {
if(addresses == null) {
addresses = new ArrayList<>();
}
this.addresses.addAll(address);
return this;
}
public BuilderLombokNormal build() {
return new BuilderLombokNormal(name, age, addresses);
}
}
}

8. @Cleanup

@Cleanup helps in automatically close the resource. This annotation takes one parameter as the closing method name. By default its value is close.

package samples.lombok;
import lombok.Cleanup;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author Jitendra Singh.
*/
public class CleanupLombok {
public static void main(String[] args) throws IOException {
@Cleanup() FileInputStream inputStream = new FileInputStream("/tmp/file.txt");
OutputStream outputStream = System.out;
int i = -1;
while((i = inputStream.read()) != -1) {
outputStream.write(i);
}
}
}
Above code is equivalent to
package samples.lombok;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author Jitendra Singh.
*/
public class CleanupLombokNormal {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("/tmp/file.txt");
try {
OutputStream outputStream = System.out;
int i = -1;
while((i = inputStream.read()) != -1) {
outputStream.write(i);
}
} finally {
if(inputStream != null) {
inputStream.close();
}
}
}
}

Happy Coding 😀😀😀 !!! If you have any feedback please comment down below.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (1)

Collapse
 
xanderyzwich profile image
Corey McCarty

Thanks for the info. I look forward to incorporating this into my work.

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up