If I add @Builder to a class. The builder method is created.
Person.builder().name(\"john\").surname(\"Smith\").build();
I have a requirem
This is my solution for the problem
import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
@Data
@Builder(builderMethodName = "privateBuilder")
public class Person {
@NonNull
private String name;
@NonNull
private String surname;
private int age;//optional
public static Url safeBuilder() {
return new Builder();
}
interface Url {
Surname name(String name);
}
interface Surname {
Build surname(String surname);
}
interface Build {
Build age(int age);
Person build();
}
public static class Builder implements Url, Surname, Build {
PersonBuilder pb = Person.privateBuilder();
@Override
public Surname name(String name) {
pb.name(name);
return this;
}
@Override
public Build surname(String surname) {
pb.surname(surname);
return this;
}
@Override
public Build age(int age) {
pb.age(age);
return this;
}
@Override
public Person build() {
return pb.build();
}
}
}
inspired by this blog post:
https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/
The simpliest solution is to add a @lombok.NonNull
to all mandatory values. The Builder will fail to build the object when mandatory fields are not set.
Here's a JUnit test to demonstrate the behavior of all combinations of final
and @NonNull
:
import static org.junit.Assert.fail;
import org.junit.Test;
import lombok.Builder;
import lombok.ToString;
public class BuilderTests {
@Test
public void allGiven() {
System.err.println(Foo.builder()
.nonFinalNull("has_value")
.nonFinalNonNull("has_value")
.finalNull("has_value")
.finalNonNull("has_value")
.build());
}
@Test
public void noneGiven() {
try {
System.err.println(Foo.builder()
.build()
.toString());
fail();
} catch (NullPointerException e) {
// expected
}
}
@Test
public void nonFinalNullOmitted() {
System.err.println(Foo.builder()
.nonFinalNonNull("has_value")
.finalNull("has_value")
.finalNonNull("has_value")
.build());
}
@Test
public void nonFinalNonNullOmitted() {
try {
System.err.println(Foo.builder()
.nonFinalNull("has_value")
.finalNull("has_value")
.finalNonNull("has_value")
.build());
fail();
} catch (NullPointerException e) {
// expected
}
}
@Test
public void finalNullOmitted() {
System.err.println(Foo.builder()
.nonFinalNull("has_value")
.nonFinalNonNull("has_value")
.finalNonNull("has_value")
.build());
}
@Test
public void finalNonNullOmitted() {
try {
System.err.println(Foo.builder()
.nonFinalNull("has_value")
.nonFinalNonNull("has_value")
.finalNull("has_value")
.build());
fail();
} catch (NullPointerException e) {
// expected
}
}
@Builder
@ToString
private static class Foo {
private String nonFinalNull;
@lombok.NonNull
private String nonFinalNonNull;
private final String finalNull;
@lombok.NonNull
private final String finalNonNull;
}
}
If you need this functionality, you can customize the builder class by yourself and you can still add @Builder
Annotation.
@Builder
public class Person {
public static class PersonBuilder {
private String name;
private PersonBuilder() {
}
public PersonBuilder(final String name) {
this.name = name;
}
}
private static PersonBuilder builder() {
return null; // or we can throw exception.
}
public static PersonBuilder builder(final String name) {
return new PersonBuilder(clientId);
}
}