I have a lot of value objects in my project.
I'm using project lombok to eliminate some boilerplate, so my value objects look like the following one:
@Value
@Accessors(fluent = true)
public class ValueObject {
private final String firstProp;
private final int secondProp;
}
Not bad, almost no boilerplate.
And now, I'm using the all-args constructor quite often in my tests. It looks quite messy, so I thought I will introduce Builder Pattern variant instead:
public class ValueObjectBuilder {
private static final int DEFAULT_VALUE_FOR_SECOND_PROP = 666;
private String firstProp = "default value for first prop;
private int secondProp = DEFAULT_VALUE_FOR_SECOND_PROP;
private ValueObjectBuilder() {}
public static ValueObjectBuilder newValueObject() {
return new ValueObjectBuilder();
}
public ValueObjectBuilder withFirstProp(String firstProp) {
this.firstProp = firstProp
return this;
}
public ValueObjectBuilder withFirstProp(int secondProp) {
this.secondProp = secondProp;
return this;
}
public ValueObject build() {
return new ValueObject(
firstProp, secondProp
);
}
}
and the code looks quite nice now:
ValueObjectBuilder
.newValueObject()
.withFirstProp("prop")
.withSecondProp(15)
.build();
Now, the problem is - as I mentioned, I have to write a lot of similar classes... I'm already tired with copy-paste'ing them.
What I'm looking for, is a black-magic-smart-tool, which will somehow generate this code for me.
I know, there is a @Builder
annotation in Lombok, but it doesn't meet my requirements. Here's why:
1) I'm unable to provide default values in lombok's Builder. Well, actually, it is possible - by implementing builder class template myself like
@Builder
public class Foo {
private String prop;
public static class FooBuilder() {
private String prop = "def value";
...
}
}
which generates some boilerplate too.
2) I can't find any way to put prefix on each field accessor in lombok's builder. Maybe @Wither could help here? But I don't know, how to use it properly.
3) The most important reason: I'm not creating a "natural" builder. As far as I understand, lombok is designed to create Builder for a given, annotated class - I don't know if there is a way to return any other object from within build()
method.
So, to sum up: Do you know any tool which could possibly help me? Or maybe all those things I mentioned are in fact possible to achieve using Lombok?
EDIT
Ok, so I probably found a solution to this particular case. With lombok we can use:
@Setter
@Accessors(chain = true, fluent = true)
@NoArgsConstructor(staticName = "newValueObject")
public class ValueObjectBuilder {
private String firstProp = "default";
private int secondProp = 666;
public ValueObject build() {
return new ValueObject(firstProp, secondProp);
}
}
Cheers, Slawek
I know this is old but if anyone else runs into this, I found an alternative solution for providing default values for a builder.
Override the builder method and provide the default values before returning a builder. So in the above case:
@Builder
public class Foo {
private String prop;
public static FooBuilder builder() {
return new FooBuilder().prop("def value");
}
}
It's not an ideal solution but beats having to override the whole builder itself or have a custom constructor (which is painful IMHO if there are a lot of variables. It would still be nice to have something along the lines of a @With or @Default annotation to handle this.
Try Bob-the-builder for eclipse. Hmm.. I guess that works best if you happen to be using eclipse! If you are not using eclipse, there are a few related projects mentioned at the bottom of the page linked here that may be useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With