Hi Guys, today I am going to talk about Project Lombok. This blog post is divided into 3 parts:
- Introduction
- Setup (Using IntelliJ idea)
- 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
Download Lombok plugin for Idea IntelliJ https://plugins.jetbrains.com/plugin/6317 as per your build number.
Goto File -> Settings -> Type Plugins in search text box at top left.
Now click Install plugin from disk. button and select the downloaded Lombok Plugin.
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.
- @Getter/@setter
- @ToString and @EqualsAndHashCode
- @NonNull
- @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
- @data
- @Value
- @builder
- @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 This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package samples.lombok; import lombok.Data; /** * @author Jitendra Singh. */ @Data public class DataLombok { private final String name; private int age; } This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characterspackage 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; | |
} |
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; | |
} |
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); | |
} | |
} | |
} |
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.
Top comments (1)
Thanks for the info. I look forward to incorporating this into my work.