The builder pattern aims to provide a flexible solution for constructing complex data structures by separating the build process from the final representation of the data structure. We use the builder pattern to get a mutable intermediate variable and an immutable final result.
Since Java ‘record‘ types are immutable by default, the builder pattern is an excellent match for records.
1. Using Nested Builder
The following User record contains a nested Builder object that takes two mandatory arguments: id and name. The other two fields use the fluent API to set data. Finally, the build() method returns a fully built record instance.
public record User(long id, String name, String email, boolean status) {
//Builder
public static final class Builder {
long id;
String name;
String email;
boolean status;
public Builder(long id, String name) {
this.id = id;
this.name = name;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder status(boolean status) {
this.status = status;
return this;
}
public User build() {
return new User(id, name, email, status);
}
}
}
We can use the Builder class as follows:
User user = new Builder(1L, "Lokesh").email("abc@domain.com").status(true).build();
Note that the record is still usable without the builder, but the builder provides an additional and flexible way to create a record instance.
2. Using Lombok @Builder
Lombok is a useful library for minimizing boilerplate code for features such as implementing the builder pattern in a class or record. Start by including the latest version of Lombok in the project. You can follow this detailed guide for Lombok installation.
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
Use the @lombok.Builder annotation with the User record to add fluent API support.
import lombok.Builder;
@Builder
record User(long id, String name, String email, boolean status) { }
We can create the User instance step by step as follows:
User user = User.builder()
.id(1l)
.name("Lokesh")
.email("email@domain.com")
.status(true)
.build();
3. Using RecordBuilder
The RecordBuilder is an opensource library for adding new features to the record types, such as:
- builder class
- copy constructors
3.1. Maven
Start with adding the RecordBuilder dependency in the project.
<dependency>
<groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder-core</artifactId>
<version>34</version>
</dependency>
Also, enable the annotation processing by adding record-builder-processor to annotation processor path.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<annotationProcessorPaths>
<path>
<groupId>io.soabase.record-builder</groupId>
<artifactId>record-builder-processor</artifactId>
<version>34</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
3.2. @RecordBuilder Annotation
The annotation enables the fluent builder API in the annotated record type.
@RecordBuilder
record User(long id, String name, String email, boolean status) { }
This annotation generates a new class with a record name appended with “Builder”. For example, for User record, the generated builder class is UserBuilder.
User user = UserBuilder.builder()
.id(1l)
.name("Lokesh")
.email("email@domain.com")
.status(true)
.build();
We can use the builder as copy constructor to create a new record from an existing record, after modifying only 1 or 2 fields. It copies the existing User‘s fields to a new User and modifies only the required fields.
User newUser = UserBuilder.builder(user)
.email("new-email@domain.com")
.status(true)
.build();
The library also enables the ‘with’ methods for a single change in any record.
User inactiveUser = UserBuilder.from(user).withStatus(false);
4. Conclusion
In this Java tutorial, we learned to implement the builder pattern style fluent API for creating records in an incremental manner. we also learned to use the RecordBuilder library to implement copy constructors on the records.
Happy Learning !!
Comments