Builder "propogation"

102 views
Skip to first unread message

Ed MacDonald

unread,
Sep 23, 2021, 4:54:31 AM9/23/21
to Project Lombok
When I'm using Jackson to create payloads for a third party API, I often end up with lots of nested classes, each annotated with @Data and @Builder, eg:
(Annotations and "public static ..." left off for readability)

class Foo {
   private Bar bar;

   class Bar {
       private Baz;

        class Baz {
             private String name;
        }
    }
}

So, to construct a Foo, I would do something like:

Foo foo = Foo.builder()
  .bar(Foo.Bar.builder()
       .baz(Foo.Bar.Baz.builder()
            .name("Ed")
            .build()
        )
       .build()
   )
   .build();

Which, no doubt, is great. However, when you take into account that most class names are longer than three characters, you may be fully qualifying them with package names, and some of these payloads get nested more than three levels deep -- it gets a little tedious.

Would it be possible for Lombok, when generating the Builder code -- to generate an additional method for any member it finds whose type is also annotated with @Builder?

for example, the Builder for Foo would have two methods:

public Foo.Builder bar(Bar bar);
and either:
public Foo.Builder bar(Function<Bar.Builder, Bar> f);
or
public Foo.Builder bar(Function<Bar.Builder, Bar.Builder> f);
(in the latter case, it would save you from typing ".build()" -- Lombok could just call it for you)

Then, the above code (assuming the latter of the two methods above) could become:
Foo foo = Foo.builder()
  .bar( (b)->
     b.baz((b)->
       b.name("Ed")
     )
   ).build();

With some Java warnings about "b" shadowing a variable already in scope (or is that an error? getting my languages mixed up).

Anyway, this would greatly simplify some code I've got at the moment.

Thank you for making Lombok!

Ed

Volodymyr

unread,
Dec 11, 2021, 4:02:34 PM12/11/21
to Project Lombok
Hello Ed. 
I was also interested in more flexible Builder for composite objects and turned out you can achieve that API by writing some additional Java code in your classes. The idea is to extend the Builder class w

@Builder(buildMethodName="internalBuild")

class Foo {
   private Bar bar;

   public static class FooBuilder {

     private Bar.BarBuilder barBuilder = Bar.builder();
     public FooBuilder bar(Consumer<Bar.BarBuilder> closure) {
        closure.accept(barBuilder);
        return this;
     }    

     public Foo build() {
       bar(barBuilder.build());
       return internalBuild();
     }
  }
}

And that's it! Surely it makes the code more complex and less concise but for some cases it might be acceptable, i.e. if you write the class once and then construct objects multiple times

I'm still thinking about adding this feature or something similar directly into Lombok, but I'm afraid it's going to take a long time to get the approval and it still won't work in Intellij IDEA before the developers of the IDEA plugin seems to support each Lombok feature by manually implementing handlers for it.

Regards Volodymyr

четверг, 23 сентября 2021 г. в 11:54:31 UTC+3, Ed MacDonald:
Reply all
Reply to author
Forward
0 new messages