Java Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

> CHECK OUT THE COURSE

1. Overview

Project Lombok's @Builder is a helpful mechanism for using the Builder pattern without writing boilerplate code. We can apply this annotation to a Class or a method.

In this quick 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.18.20</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 merely 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 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 the toBuilder() method to our Class. When we invoke the toBuilder() method, it returns a builder initialized with the properties of the instance it's 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 want, and build() a new instance.

If we need to specify the required fields, we can use the annotation configuration to create an auxiliary builder:

@Builder(builderMethodName = "internalBuilder")
public class RequiredFieldAnnotation {
    @NonNull
    private String name;
    private String description;

    public static RequiredFieldAnnotationBuilder builder(String name) {
        return internalBuilder().name(name);
    }
}

In this case, we're hiding the default builder as internalBuilder and creating our own. Thus, when we create the builder, we must provide the required parameter:

RequiredField.builder("NameField").description("Field Description").build();

Also, to make sure our field exists, we can add the @NonNull annotation.

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 also use it on methods. We'll use this ability to work around not being able to modify or extend ImmutableClient.

Then 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 let's 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 brief article, we used Lombok's @Builder annotation on a method to create a builder for a final Class, and we learned how to make some of the Class fields required.

Code samples, as always, can be found over on GitHub.

Java bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
Comments are closed on this article!