Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] "inline" Builder methods that create a field from its constructor arguments #3736

Open
timo-a opened this issue Sep 1, 2024 · 0 comments

Comments

@timo-a
Copy link

timo-a commented Sep 1, 2024

Describe the feature
For a class Foo with a field bar of type Bar with constructor Bar(String a, int b) a @Builder today provides a method
FooBuilder::bar(Bar bar) that takes an instance of a Bar.
This feature request proposes that in addition an "inline" builder method should be generated for any constructor of Bar, e.g. FooBuilder::bar(String a, int b).
Such Methods then take the constructor arguments of Bar and create an instance as part of their method body.
I'm scoping this feature request to fields that are records since I doubt it is feasible for classes (see below, additional context point 3), but I don't mind if it comes for ordinary classes as well.

Describe the target audience
Programmers that use @Builder on classes whose constructors take records as arguments, and these records are instantiated on the spot. They might be using Domain driven design (DDD) and thus not use primitives as their smallest building blocks but (record) classes. As a consequence the builder would take next to no primitives but mostly records, which makes for a lot of redundancy. E.g. in a Unit test a (school) class is created:

var expected = Class.builder().
    .className(new ClassName("9b"))//year 9, student batch "b"
    .teacher(new Teacher("John", "Smith", 42))
    .classAnimal(new Animal("fido", "dog")) 
    .pupil(new Pupil("Alice", "Aberg"))
    .pupil(new Pupil("Bob", "Bberg"))
    .pupil(new Pupil("Carol", "Cberg"))
    .build();

Instead they want to write the more concise:

var expected = Class.builder().
    .className("9b")//year 9, student batch "b"
    .teacher("John", "Smith", 42)
    .classAnimal("fido", "dog"))
    .pupil("Alice", "Aberg")
    .pupil(Bob", "Bberg")
    .pupil("Carol", "Cberg")
    .build();

Additional context
One might argue against this feature by saying that:

  1. A constructor should be used instead:
 var expected = new Class(
    new ClassName("9b")//year 9, student batch "b"
    new Teacher("John", "Smith", 42)
    new Animal("fido", "dog") 
    new Pupil("Alice", "Aberg")
    new Pupil("Bob", "Bberg")
    new Pupil("Carol", "Cberg")
    );
  1. There will be ambiguity, e.g. from self-referencing tree structures like record Tree(Tree subtree) because it is not clear if the tree that is passed should be assigned to the field or if it is rather a constructor argument. To avoid this the "inline methods" could simply have a suffix instead of overloading, e.g. fooFromArgs(...) or ideally something much shorter.
  2. This cannot work for classes and their sub classes because there are too many, and some might be defined in a place that is not accessible at build time. => that's why I'm scoping this feature request to records since they can't inherit. Addressed here anyway for transparency.
    I guess you could also decide to only generate inline builder methods for the class of the field and not allow constructors of sub classes. But that might come as a surprise to developers who don't read the fine print.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant