0

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?

AllirionX
  • 1,073
  • 6
  • 13
  • Is it a requirement to use the class `Undefined`? because a simple `newTitle!=null` would work in this case. – Marc Sep 16 '20 at 04:41
  • AFAIK, it would not be possible have a check at `@ObtainVia`, though I have never used it. – code_mechanic Sep 16 '20 at 04:53
  • @Marc It is a requirement to use some sort of wrapper (I could use Optional instead of Undefined but I would need to have null Optional for undefined values, which is not what Optional should be used for). Using a String and `newTitle != null` would not work as we cannot differenciate a null value that as not been set (the title should not be updated) from a null value that has been set (the title should be updated to null). – AllirionX Sep 16 '20 at 04:56

1 Answers1

1

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.
}
Jan Rieke
  • 7,027
  • 2
  • 20
  • 30
  • My goal here is to automate the customized part, as I have a lot of commands with a lot of undefined fields. Plus I want to make sure all new command builders are correctly implemented with the same pattern. – AllirionX Sep 21 '20 at 00:17
  • That's not possible with Lombok. – Jan Rieke Sep 21 '20 at 12:57