Migrating From Lombok to Records in Java

Samuel Catalano
The Fresh Writes
Published in
4 min readJan 8, 2024

Over time, Java has progressed as a programming language, incorporating new capabilities and enhancements to boost the efficiency of developers and the readability of code. One significant addition with the launch of Java 14 is the inclusion of records, providing a succinct method to establish immutable classes that carry data.

If you’ve been utilising Lombok to minimise repetitive code in your Java classes, it might be beneficial to transition to records for a more standardised and native solution.

This article will delve into the procedure of transitioning Java code from Lombok to Java records, illustrated with hands-on examples.

Why Migrate From Lombok to Records?

Lombok is extensively embraced within the Java community for its capability to diminish verbosity through the automated creation of getters, setters, constructors, and repetitive code. Although Lombok proves effective, the advent of records presents a standardized, built-in approach to defining immutable data classes. Records provide enhanced integration with the language and are inherently supported by a variety of 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 given illustration, we establish a Movie class containing two attributes (title and releaseYear) within the constructor parameter roster. The compiler autonomously produces the constructor, equals(), hashCode(), and toString() functions, mirroring the functionality akin to what Lombok would 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 inherently create a concise and articulate constructor that sets all fields. In the instance of the Series record, the constructor accepts three parameters that match the fields: title, startYear, and endYear.

Handling Default Values

Occasionally, it becomes essential to manage default values for specific fields. In Lombok, this can be accomplished through the utilization of @Builder or custom methods. When working with records, default values can be directly assigned 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, initial values are explicitly defined within the constructor’s code. Should the title or director happen to be null, default values will be allocated.

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 the Lombok, the @Builder annotation creates a builder class tailored to the FilmWithLombok class. This builder offers a seamless interface for constructing instances, incorporating 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();

In the case of Java records, we establish a static nested Builder class inside the record. This builder class possesses methods for defining each field and a build method to instantiate the record. This offers a comparable fluent API as observed in the Lombok illustration.

Utilizing builders with records or Lombok offers a handy and legible method to create instances, particularly when interacting with classes that have numerous fields. Opt for the strategy that best suits your inclinations and project necessities.

Conclusion

Migrating from Lombok to Java records unlocks a treasure trove of built-in language features, boosting code maintainability and readability. Records streamline the creation of immutable data objects, rendering external libraries like Lombok redundant. This article equips you with the tools to effortlessly migrate your code and unlock the power of modern Java 14+. Just a heads-up: remember to update your build configuration and dependencies, and get ready to revel in the newfound clarity and conciseness of your code!

Happy coding ;)

Thanks for reading. Happy learning 😄

Do support our publication by following it

Also refer to the following articles

--

--

Samuel Catalano
The Fresh Writes

Samuel is a Software Engineer from Brazil with main interests in Java, Spring Boot, Quarkus, Microservices, Docker, Databases, Kubernetes, and Clean Code