How to have mandatory fields and validated fields in @Builder?

9,060 views
Skip to first unread message

Keyhan

unread,
Feb 17, 2016, 11:39:12 AM2/17/16
to Project Lombok
Hi, I want to use the @Builder annotation of Lombok to build my Pojo. But I want some fields some fields to be mandatory and some not, also I want to validate all the fields with different logic. How can I do that?

regards
K

Michael

unread,
Feb 20, 2016, 1:56:58 PM2/20/16
to Project Lombok
You could create your Pojo using builder annotation and validate it using JSR-303

Jeff

unread,
Feb 25, 2016, 2:36:00 PM2/25/16
to Project Lombok
Are you using java 8?

Justin Ryan

unread,
Mar 23, 2016, 9:06:43 PM3/23/16
to project...@googlegroups.com
I've seen the pattern where multiple builders are created to enforce required fields. For example:

class Model {
    @NonNull A a;
    B b;
    C c;
    ModelBuilderWithoutA builder() { ... }
}

interface ModelBuilder {
    ModelBuilder setB(B b)
    ModelBuilder setC(C c)
    Model build()
}

interface ModelBuilderWithoutA {
    ModelBuilder setA(A a)
    ModelBuilderWithoutA setB(B b)
    ModelBuilderWithoutA setC(C c)
}

In the above example, you literally can't run build() until A has been set, because you would have had to call setA to get a ModelBuilder. You can also set B and C before or after A being set. This provides for a type-safe builder for required fields. As you can imagine, the combinatorial matrix of builders to maintain this setup is tedious, but something like Lombok could do the generation and hide all the messy details away.

If someone wanted to work on this, where would they start?

--
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.
For more options, visit https://groups.google.com/d/optout.

pbihler

unread,
Mar 24, 2016, 4:27:37 AM3/24/16
to Project Lombok


Am Donnerstag, 24. März 2016 02:06:43 UTC+1 schrieb Justin Ryan:
I've seen the pattern where multiple builders are created to enforce required fields. (...)
 
If someone wanted to work on this, where would they start?

Thats sounds like a promising idea - I would start extending the HandleBuilder.java classes.

Pascal

improved builder pattern

unread,
Dec 15, 2016, 6:24:40 AM12/15/16
to Project Lombok
this is my solution:

@Data
@Builder(builderMethodName = "privateBuilder")
public class Person {
@NonNull
private String name;
@NonNull
private String surname;
private int age;//optional


//disable public builder
private static PersonBuilder privateBuilder(){
return Person.privateBuilder();
}


public static Url safeBuilder() {
return new Builder();
}

interface Url {
Surname name(String name);
}

interface Surname {
Build surname(String surname);
}

interface Build {
Build age(int age);

Person build();
}

public static class Builder implements Url, Surname, Build {
PersonBuilder pb = Person.privateBuilder();

@Override
public Surname name(String name) {
pb.name(name);
return this;
}

@Override
public Build surname(String surname) {
pb.surname(surname);
return this;

}

@Override
public Build age(int age) {
pb.age(age);
return this;
}

@Override
public Person build() {
return pb.build();
}
}
}

Reinier Zwitserloot

unread,
Mar 2, 2017, 8:00:11 AM3/2/17
to Project Lombok
Don't work on this. We won't accept it.

The real solution is to have an IDE plugin. You need:

1. Annotations: A. That mark methods as optional, mandatory, and perhaps 'multiple' (can be called more than once). (these go on the 'setters') B. Mark a method as the 'ensure calls' method. (this goes on the build() method, C. That call ensuring needs to be performed on the return expression (this goes on builder()).

2. The plugin recognises calls to builder() via the annotation that's there, and will then adjust the autocomplete dialog as follows: build() will be greyed out if you've forgotten at least 1 mandatory. Methods that have already been called and aren't multiple are also grey or possibly something else. Mandatories (that haven't been called) are bold. Optionals (and possibly multi-mandatories that have already been called) are normal light black or whatever your IDE does.

3. The plugin recognises calls to build() and emits a warning that a mandatory call has not been placed.


This is vastly superior to any other solution. Because I thought it up, I no longer find any 'generate a whole bunch of interfaces' strategy palatable now.


On Thursday, March 24, 2016 at 2:06:43 AM UTC+1, Justin Ryan wrote:
I've seen the pattern where multiple builders are created to enforce required fields. For example:

class Model {
    @NonNull A a;
    B b;
    C c;
    ModelBuilderWithoutA builder() { ... }
}

interface ModelBuilder {
    ModelBuilder setB(B b)
    ModelBuilder setC(C c)
    Model build()
}

interface ModelBuilderWithoutA {
    ModelBuilder setA(A a)
    ModelBuilderWithoutA setB(B b)
    ModelBuilderWithoutA setC(C c)
}

In the above example, you literally can't run build() until A has been set, because you would have had to call setA to get a ModelBuilder. You can also set B and C before or after A being set. This provides for a type-safe builder for required fields. As you can imagine, the combinatorial matrix of builders to maintain this setup is tedious, but something like Lombok could do the generation and hide all the messy details away.

If someone wanted to work on this, where would they start?

Nico Korthout

unread,
Nov 18, 2017, 4:11:12 AM11/18/17
to Project Lombok
Today, I've been discussing this topic with my team, because we ran into similar problems. We're glad you acknowledge the problem, however we do not share your opinion that an IDE plugin is a superior solution. We are curious why you believe that to be the case. 

In the meantime, please consider our arguments in favor of a pure-code solution:
  1. A pure-code solution would cause a failing build in a build pipeline due to a compile error, while an IDE plugin cannot;
  2. Not every developer uses the same IDE, which means the plugin would have to be developed & maintained for multiple IDE's;
  3. It might be the case that not every developer will have this plugin installed, leaving possible inconsistencies in code quality.
We look forward to your reply, but we are also welcome to an open discussion with anyone that wants to contribute. Please feel free to reply.

All the best,

Nico

Op donderdag 2 maart 2017 14:00:11 UTC+1 schreef Reinier Zwitserloot:

Martin Grajcar

unread,
Nov 23, 2017, 9:09:47 PM11/23/17
to project...@googlegroups.com
On Thu, Nov 16, 2017 at 5:22 PM, Nico Korthout <nico.k...@gmail.com> wrote:
Today, I've been discussing this topic with my team, because we ran into similar problems. We're glad you acknowledge the problem, however we do not share your opinion that an IDE plugin is a superior solution. We are curious why you believe that to be the case. 

I can't speak for the Lombok team, but I recall them refusing this because of the combinatorial explosion of needed classes. With ten mandatory fields allowed to be filled in any order, you'd need 1024 classes, which would add a few megabytes of class files, slow down class loading and kill your IDE experience.

Another thing is a builder enforcing some fixed order. It would need just ten classes and may be pretty useful sometimes, when the flexibility loss is an advantage. I wrote one such builder using a private Lombok builder. I'm not sure, if such a builder is sufficiently useful in general, as changed requirements may make the chosen fixed order wrong and force you to rewrite a lot of code.
 
In the meantime, please consider our arguments in favor of a pure-code solution:
  1. A pure-code solution would cause a failing build in a build pipeline due to a compile error, while an IDE plugin cannot;
  2. Not every developer uses the same IDE, which means the plugin would have to be developed & maintained for multiple IDE's;
  3. It might be the case that not every developer will have this plugin installed, leaving possible inconsistencies in code quality.
The IDE plugin should be augmented with a static analyzer or corresponding rules should be added to a few commonly used analyzers. This means quite some more work.

There are also things which the plugin could do better than a code generator. For example, you may want to set fields anytime, but you don't want to set the same field multiple times in a single snippet. At the same time, you don't want to forbid overwriting them when a builder gets passed around. I mean the following is most probably a mistake

X.builder().a("a").b("b").a("a");

while this is right

return finishX(X.builder().a("a").b("b"));

X finishX(X.Builder builder) {
    return (cond() ? builder.a("aaaa") : builder.c("c")).build();
}

Reply all
Reply to author
Forward
0 new messages