How to Migrate From Lombok to Java Records

6 min read
May 27, 2024

Java has evolved a great deal as a programming language, continuously adding new features and improvements to make developers' work more efficient and code more readable. A notable update in Java 14 is the introduction of records, which offer a streamlined way to create immutable classes designed to hold data.

If you’ve been using Lombok to cut down on redundant code in your Java classes, it could be worthwhile to switch to records for a more standardized and native approach.

In this article, we will explore the process of converting Java code from using Lombok to utilizing Java records, demonstrated through practical examples.

Why Migrate From Lombok to Records?

Lombok has gained widespread popularity in the Java community due to its ability to reduce boilerplate code by automatically generating getters, setters, constructors, and other repetitive elements. While Lombok is indeed powerful, the introduction of records offers a more standardized and built-in way to create immutable data classes. Records are better integrated with the language and are natively supported by many tools and frameworks.

Migrating Getters and Setters

Lombok Example

import lombok.Data;

@Data
public class Movie {
private String title;
private int releaseYear;
}

Record Example

public record Movie(String title, int releaseYear) {
}

In the provided illustration, we define a Movie class with two attributes, title and releaseYear, specified in the constructor parameter list. The compiler independently generates the constructor, equals(), hashCode(), and toString() methods, replicating the functions that Lombok would typically create.

Migrating Constructors

Lombok Example

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
public class Series {

private String title;
private int startYear;
private int endYear;

}

Record Example

public record Series(String title, int startYear, int endYear) {
}

Records naturally provide a clear and efficient constructor that initializes all fields. For the Series record, this constructor takes three parameters corresponding to the fields: title, startYear, and endYear.

Handling Default Values

At times, it's crucial to handle default values for certain fields. In Lombok, you can achieve this using the @Builder annotation or through tailored methods. For records, you can set default values straight within the constructor.

Lombok Example

import lombok.Builder;

@Builder
public class Film {
private String title;
private String director;
private int releaseYear;
}

Record Example

public record Film(String title, String director, int releaseYear) {

public Film {

if (Objects.isNull(title)) {
this.title = "Unknown Title";
}

if (Objects.isNull(director)) {
this.director = "Unknown Director";
}
}
}

In the Film class's record instance, the constructor code clearly sets the initial values. If the title or director is null, default values will be assigned.

Using Builder With Lombok

import lombok.Builder;

@Builder
public class FilmWithLombok {
private String title;
private String director;
private int releaseYear;
}

// Example of using the builder:
FilmWithLombok film = FilmWithLombok
.builder()
.title("Batman - The Dark Knight")
.director("Christopher Nolan")
.releaseYear(2008)
.build();

In Lombok, the @Builder annotation generates a builder class specifically for the FilmWithLombok class. This builder class provides an intuitive interface for creating instances, using optional and chainable setter methods.

Using Builder With Java Record

public record FilmWithRecord(String title, String director, int releaseYear) {

public static class Builder {

private String title;
private String director;
private int releaseYear;

public Builder title(String title) {
this.title = title;
return this;
}

public Builder director(String director) {
this.director = director;
return this;
}

public Builder releaseYear(int releaseYear) {
this.releaseYear = releaseYear;
return this;
}

public FilmWithRecord build() {
return new FilmWithRecord(title, director, releaseYear);
}

}
}

// Example of using the builder:
FilmWithRecord film = new FilmWithRecord
.Builder()
.title("Batman - The Dark Knight")
.director("Christopher Nolan")
.releaseYear(2008)
.build();

For Java records, we create a static nested Builder class within the record itself. This Builder class comes with methods for setting each field and includes a build method to create the record instance. It provides a similar fluent API as demonstrated in the Lombok example.

Using builders with records or Lombok provides a convenient and clear approach to create instances, especially when dealing with classes that have many fields. Choose the method that aligns most with your preferences and project requirements.

Conclusion

Switching from Lombok to Java records opens up a wealth of native language features that enhance code maintainability and readability. Records simplify the process of creating immutable data objects, making external libraries like Lombok unnecessary. This article provides you with the steps to seamlessly transition your code and harness the capabilities of modern Java 14+. Just a heads-up: remember to update your build configuration and dependencies, and prepare to enjoy the improved clarity and conciseness of your code!

Read more in Tech