Partner – Microsoft – NPI (cat=Java)
announcement - icon

Microsoft JDConf 2024 conference is getting closer, on March 27th and 28th. Simply put, it's a free virtual event to learn about the newest developments in Java, Cloud, and AI.

Josh Long and Mark Heckler are kicking things off in the keynote, so it's definitely going to be both highly useful and quite practical.

This year’s theme is focused on developer productivity and how these technologies transform how we work, build, integrate, and modernize applications.

For the full conference agenda and speaker lineup, you can explore JDConf.com:

>> RSVP Now

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.30</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.

Course – LS (cat=Java)

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

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!