inferred / FreeBuilder

Automatic generation of the Builder pattern for Java
Apache License 2.0
838 stars 101 forks source link

Enhancement: Add nested builder functions #442

Closed NathanJAdams closed 3 years ago

NathanJAdams commented 3 years ago

Hi, awesome library!

I have some classes I want to add builders for that have a nested structure, here's a noddy example:

@FreeBuilder
interface Parent {
    String name();
    Child child();
    ...
}

@FreeBuilder
interface Child {
    String nickname();
    ...
}

To add a child to a parent builder, it needs something like this: Parent.builder().child(Child.builder().nickname("Freddy").build()).build();

What might be interesting is to allow something like this: Parent.builder().childBuilder().nickname("Freddy").build().build();

I appreciate it's a pretty minor reduction in boilerplate, but think it adds an option that might look nicer, and think it could be done with the following idea:

Have 2 constructors in each builder, a default one and another one which takes a function which takes a single parameter of the built object and returns a generic value. Then in the build() function if the function wasn't given proceed as usual, and if it was given, build the object as normal, but then invoke the given function with the built object and return the result.

This could then be used by a parent builder to add/set the child object as normal then return itself behind the scenes to continue building the parent.

alicederyn commented 3 years ago

We currently support the following:

Parent.builder().mutateChild(b -> b.nickname("Freddy")).build();

This is just a smidge shorter than your suggestion, and doesn't require a whole separate Child.Builder class (which unfortunately yours would as the build method has a different signature).

Does this work for you?

NathanJAdams commented 3 years ago

Ah fantastic that looks even better! Thank you!