I have another approach using @Delegate
and Inner Class
, which supports "computed values" for the excluded fields.
First, we move the fields to be excluded into an Inner Class
to avoid Lombok from including them in the Builder.
Then, we use @Delegate
to expose Getters/Setters of the builder-excluded fields.
Example:
@Builder
@Getter @Setter @ToString
class Person {
private String name;
private int value;
/* ... More builder-included fields here */
@Getter @Setter @ToString
private class BuilderIgnored {
private String position; // Not included in the Builder, and remain `null` until p.setPosition(...)
private String nickname; // Lazy initialized as `name+value`, but we can use setter to set a new value
/* ... More ignored fields here! ... */
public String getNickname(){ // Computed value for `nickname`
if(nickname == null){
nickname = name+value;
}
return nickname;
}
/* ... More computed fields' getters here! ... */
}
@Delegate @Getter(AccessLevel.NONE) // Delegate Lombok Getters/Setters and custom Getters
private final BuilderIgnored ignored = new BuilderIgnored();
}
It will be transparent to outside of this Person
class that position
and nickname
are actually inner class' fields.
Person p = Person.builder().name("Test").value(123).build();
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=null, nickname=Test123))
p.setNickname("Hello World");
p.setPosition("Manager");
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=Manager, nickname=Hello World))
Pros:
- Do not force the excluded fields to be
final
- Support computed values for the excluded fields
- Allow computed fields to refer to any fields set by the builder (In other words, allow the inner class to be non-static class)
- Do not need to repeat the list of all fields (Eg. listing all fields except the excluded ones in a constructor)
- Do not override Lombok library's
@Builder
(Eg. creating MyBuilder extends FooBuilder
)
Cons:
- The excluded fields are actually fields of
Inner Class
; however, using private
identifier with proper Getters/Setters you can mimic as if they were real fields
- Therefore, this approach limits you to access the excluded fields using Getters/Setters
- The computed values are lazy initialized when Getters are invoked, not when
.build()
.