1

I'm working on a project which uses the Builder pattern. But this team uses Builder constructor arguments for the "required" attributes, and the builder "setters" for the optional stuff.

Here is an example where name is required and age is optional.

Person person = Person.Builder("Bob Belcher").age(23).build();

When I apply @Builder, is there anyway I can instruct Lombok to add specified attributes in the builder's constructor?

Gautham M
  • 4,816
  • 3
  • 15
  • 37
Sean256
  • 2,849
  • 4
  • 30
  • 39
  • 1
    Short answer: no. You can refactor the code to use no-args builders relatively easily (if you are using intellij). – Augusto Aug 24 '21 at 17:44
  • I would maybe do that if this project didn't have other people who have a preference already established. Plus, I see why they like it, it's a nice way to enforce required attributes at compile time. – Sean256 Aug 24 '21 at 17:49

1 Answers1

2

I would suggest an overloaded static method builder taking the required arguments and returning the builder object. Thus lombok won't be generating a builder method since we have already defined it.

@Builder
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Person {
    // fields....
    public static PersonBuilder builder(String name) {
        return new PersonBuilder().name(name);
    }       

}

The private access level could enforce that the object be created using only the of method.

For the requirement of "builder setters for the optional stuff", such that you cannot invoke name() on the builder object, you may try to override the builder methods for the required arguments to make it private. Refer here. (Also related use case)

@Builder
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Person {
    // fields....
    public static PersonBuilder builder(String name) {
        return new PersonBuilder().name(name);
    }       

    public static class PersonBuilder  {
        private PersonBuilder name(String name) {
            this.name = name;
            return this;
        }
    }
}

// invoke as 
Person.builder("my name").age(23).build();
Gautham M
  • 4,816
  • 3
  • 15
  • 37
  • 1
    You can simply reuse the `builder()` method and give it parameters. Lombok will detect that there is already a method named `builder` and won't create another (overloaded) one, regardless of its parameters. In this way, there is no need to make the regular method private. – Jan Rieke Aug 25 '21 at 19:46