1. Overview
Project Lombok’s @Builder is a useful mechanism for using the Builder pattern without writing boilerplate code. We can apply this annotation to a Class or a method.
In this brief tutorial, we’ll look at the different use cases for @Builder.
2. Maven Dependencies
First, we need to add Project Lombok to our pom.xml:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20.0</version> </dependency>
Maven Central has the latest version of Project Lombok here.
3. Using @Builder on a Class
In the first use case, we’re simply implementing a Class, and we want to use a builder to create instances of our class.
The first and only step is to add the annotation to the class declaration:
@Getter @Builder public class Widget { private final String name; private final int id; }
Lombok does all of the work for us. We can now build a Widget and test it:
Widget testWidget = Widget.builder() .name("foo") .id(1) .build(); assertThat(testWidget.getName()) .isEqualTo("foo"); assertThat(testWidget.getId()) .isEqualTo(1);
If we want to create copies or near-copies of objects, we can add the property toBuilder = true to the @Builder annotation:
@Builder(toBuilder = true) public class Widget { //... }
This tells Lombok to add a toBuilder() method to our Class. When we invoke the toBuilder() method, it returns a builder initialized with the properties of the instance it is called on:
Widget testWidget = Widget.builder() .name("foo") .id(1) .build(); Widget.WidgetBuilder widgetBuilder = testWidget.toBuilder(); Widget newWidget = widgetBuilder.id(2).build(); assertThat(newWidget.getName()) .isEqualTo("foo"); assertThat(newWidget.getId()) .isEqualTo(2);
We can see in the test code that the builder class generated by Lombok is named like our class, with “Builder” appended to it — WidgetBuilder in this case. We can then modify the properties we wish and build() a new instance.
4. Using @Builder on a Method
Suppose we’re using an object that we want to construct with a builder, but we can’t modify the source or extend the Class.
First, let’s create a quick example using Lombok’s @Value annotation:
@Value final class ImmutableClient { private int id; private String name; }
Now we have a final Class with two immutable members, getters for them, and an all-arguments constructor.
We covered how to use @Builder on a Class, but we can use it on methods, too. We’ll use this ability to work around not being able to modify or extend ImmutableClient.
Next, we’ll create a new class with a method for creating ImmutableClients:
class ClientBuilder { @Builder(builderMethodName = "builder") public static ImmutableClient newClient(int id, String name) { return new ImmutableClient(id, name); } }
This annotation creates a method named builder() that returns a Builder for creating ImmutableClients.
Now we can build an ImmutableClient:
ImmutableClient testImmutableClient = ClientBuilder.builder() .name("foo") .id(1) .build(); assertThat(testImmutableClient.getName()) .isEqualTo("foo"); assertThat(testImmutableClient.getId()) .isEqualTo(1);
5. Conclusion
In this article, we used Lombok’s @Builder annotation on a method to create a builder for a final Class.
Code samples, as always, can be found over on GitHub.