javabuilderlombokfreebuilder

Automatic generation of builder pattern that boxes generic type


A command is instantiated by a Builder, that, when setting values, wraps them in an Undefined object (this is then used in the execute method to set the book's title only if the newTitle has been set).

The command class:

public class UpdateBookCommand {
  Book book;
  Undefined<String> newTitle;

  public Book execute(){
    if(newTitle.isDefined())
      this.book.setTitle(this.newTitle.get());
    return this.book;
  }

  public static class Builder {
    Book book;
    Undefined<String> newTitle = Undefined.instance();

    public Builder(Book book) {
      this.book=book;
    }

    public Builder newTitle(String newTitle){
      this.newTitle=Undefined.of(newTitle);
    }
    
    public UpdateBookCommand build() {
      UpdateBookCommand command = new UpdateBookCommand();
      command.newTitle=this.newTitle;
      return command;
    }
  }
}

This pattern works well and I intend to use it for all my commands, but requires a lot of boilerplate code that I would like to automatically generate using Lombok @Builder or FreeBuilder or any other code generation tool, but I cannot find how to automatically generate the Undefined wrapper.

Both tools would generate

public Builder newTitle(Undefined<String> newTitle)){
  this.newTitle=newTitle;
}

instead of

public Builder newTitle(String newTitle){
  this.newTitle=Undefined.of(newTitle);
}

Is there a way to change the template of the code generated by the @Builder or @Freebuilder annotations, or any other tool I could use instead?


Solution

  • You can use Lombok's @Builder and customize the parts that don't fit your needs. Anything that already exists in the builder class will be silently ignored by Lombok, and everything else will be generated as usual.

    In your example, this looks as follows:

    @Builder
    public class UpdateBookCommand {
      Book book;
      Undefined<String> newTitle;
    
      public static class UpdateBookCommandBuilder {
        public Builder newTitle(String newTitle) {
          this.newTitle=Undefined.of(newTitle);
        }
      }
      // Your methods here.
    }