@StepBuilder - new feature to generate builder with step builder pattern

198 views
Skip to first unread message

Dariusz Rackowski

unread,
Jul 24, 2019, 7:09:31 AM7/24/19
to Project Lombok
I used a lot builder pattern but with other than standard builder pattern.
I'm using my own maven plugin to generate builder in source code files with builder in step builder pattern (mostly using javaparser.org library).

I found recently that there is plugin to intelliJ for this kind of builder so instead of writing what does it mean "StepBuilder" I will put here link to this project: http://www.svlada.com/step-builder-pattern/
I'm generating automatically almost same code like in examples.

Instead of using maven plugin or re-generating code by IntelliJ plugin I would prefer to have it in lombok. 
So I thought about contributing and rewrite it there - if I will be able to get into lombok sources knowledge enought ;) 

Has it a potential to fit into (at least) experimental in published version?

Mat Jaggard

unread,
Jul 24, 2019, 7:23:24 AM7/24/19
to project-lombok
This kind of concept (albeit without a name) has been discussed on this forum lots of times but I think this is the best description and possible implementation I've seen. In addition, because the existing builder could be used and just the interfaces are new, it seems easier to implement.

Presumably the order in which the builder must be created would be the order of the final fields in the class, followed by all non-final? Should the "Build" interface be removed though and the underlying builder be returned at that point? That way, a user could pass it (with default values for required fields) to some other code and all fields would be configurable?

Many thanks,
Mat.

--
You received this message because you are subscribed to the Google Groups "Project Lombok" group.
To unsubscribe from this group and stop receiving emails from it, send an email to project-lombo...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/project-lombok/66fe555f-ae6f-42b7-a282-30f930ec0008%40googlegroups.com.

Reinier Zwitserloot

unread,
Jul 24, 2019, 7:24:38 AM7/24/19
to Project Lombok
You're not the only one to ask. You're misled. This is not a good idea.

Here is what you WANT:

[1] When writing your source code, you want _GUIDANCE_: Best case scenario, you want the following guidance: Which methods should not be called again because you already called them (so, they are set-once builder methods that you already called), which methods must still be called before you can continue to calling build() (mandatory builder methods that haven't yet been called), which methods can still be called but aren't required (set-multi methods such as the ones @Singular makes, or builder-setters that have defaults).

[2] During writing it and afterwards (during compilation, your CI tool, your IDE's problems & warnings list, commit hooks – one or more of those) a warning or possibly error indicating something that's wrong with your builder call, such as omitting a mandatory prior to calling build(), or calling a set-once method multiple times.


So, you should aim for precisely that. No more, and no less. Your explosion of types gets you this, in a really silly way: You get a ton of types, trying to send half-built builders around other code is insane (you need to start putting the intermediate interfaces into your APIs), you still see all the java.lang.Object methods in the mix, you have no good way of dealing with optional fields, you are forced to call the mandatories in a specific order and have in fact eliminated the ability to split up the code for building across multiple different methods.


There's absolutely no reason you can't just get what you want: The IDE can and should be specific. Your autocomplete dialog should render in bold all mandatory calls, render in normal all optional available calls, and render in grey any calls that exist but which you should not make (build() if mandatories aren't covered yet, for example). The bold ones should be at the top of the box, of course. That's what you want. This will also then work with ALL builders already in existence. Potentially they'd have to add some annotations but that's API-wise backwards compatible.


Given that this is the option, the crappy half-baked way to get this via @StepBuilder is not acceptable.

Also, note that the notion 'I return a PersonBuilder object whose name() method has already been called' is something that the StepBuilder would convey via the notion of a PersonBuilderAfterStepName. But the checker framework ( https://checkerframework.org/ ) does it right: Types can carry tags (for example: I return a String and it will not be null; the nullity is a tag), and the checker framework lets you add a tag to your 'PersonBuilder' as it shows up in for example a return type: name() has been called. You can annotate your build() method to be allowed only if the receiver is of type 'PersonBuilder for which name() and birthDate() have been called.

We're working on lombok generating these markers so that you can then use the checker framework for linting checks. It's then up to IDE builders and/or plugin builders to add the guidance on top of that.

THAT is where the effort to work on this problem should go: Linters and IDE plugins. NOT in generating 18 million interfaces.

TL;DR: Project Lombok's official position is that we will not add this, will deny PRs, and consider the pattern a half-baked inappropriate solution to the problem; instead, look to address this issue by making the tools (IDE and linter) aware of the builder pattern. Lombok will support any such linter and/or IDE tool as best we can, and we will consider any PR that adds such support. In fact, we're working on one for the checker framework's take on this now.

Michael Ernst

unread,
Jul 24, 2019, 2:04:02 PM7/24/19
to project...@googlegroups.com
The proposed Step Builder Pattern addresses a real problem:  incorrect use of the Builder Pattern, such as failing to set a needed field.

We have built a free javac plugin that achieves the same purpose.
It gives you a compile-time warning if your code might not set a needed field before calling `build()`.
It works out-of-the-box with Lombok.
You don't have to rewrite your code or introduce new interfaces.

The tool is currently in limited beta.  We would love your feedback on it!
Please send me email if you would like to try it.
It currently requires that
 * you use the Gradle build system (say, via the io.freefair.lombok Gradle plugin), or
 * your build script produces delomboked code.

                    -Mike

--

Dariusz Rackowski

unread,
Jul 24, 2019, 2:44:39 PM7/24/19
to Project Lombok
Thank You for answer - I'm glad I asked before burning my time on writing code in lombok project. 
So I need to stay with my maven plugin.

I can shortly describe as an addition how this plugin works:
1. plugin is executed on all classes annotated with special annotation
2. it tries to find @AllArgsConstructor (lombok) annotation or constructor with parameters
3. it generates inner class "FluentBuilder" with whole needed code:
3a. on start build process there is one object created with all fields (object of class builder which implements all "FieldStepInterfaces")
3b. on each step same object is returned but with different interface (so I prevent creating many objects in each step)
3c. on build method call all fields are passed to constructor

While using generated StepBuilder IDE hints quickly what should be set next and next :) 
Another great thing with this solution is when I add new field, all places where I missed code are not compiling.
I didn't implement "optional" setters because I don't need them.

I know it's very simple and limited solution but It helps objects not using constructor (which is unreadable on more than 3 parameters) or using builder and wondering which field I still missed or if I doubled setting any. I know that using standard @Builder has a lot of use cases and then it's great but while trying to create new object with required fields - is not easy to use and it's not preventing mistakes.


  - Darek

Dariusz Rackowski

unread,
Jul 24, 2019, 2:48:51 PM7/24/19
to Project Lombok
Hi Michael,
thanks for proposition but probably I'll stay with maven plugin autogenerating code. 
But if you want I can try to test your plugin in spare time. Please sent me information about that, my email login is "drackows" on google mail.

  - Darek
To unsubscribe from this group and stop receiving emails from it, send an email to project...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages