Let's suppose there is the following exemplary class which is not under my control, i.e. I cannot change its behavior.
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class RegistrationRequest {
private String email;
private String emailRepeat;
private String password;
private String passwordRepeat;
}
I'd like to use Lombok @Builder
to build test data for this class, so I put the @Builder
annotation on the method level like this:
public class SomeTestUtils {
public static final String DEFAULT_EMAIL = "[email protected]";
public static final String DEFAULT_EMAIL_REPEAT = "[email protected]";
public static final String DEFAULT_PASSWORD = "my-password";
public static final String DEFAULT_PASSWORD_REPEAT = "my-password";
@Builder(builderMethodName = "aRegistrationRequest", setterPrefix = "with")
public static RegistrationRequest buildRegistrationRequest(String email, String emailRepeat, String password, String passwordRepeat) {
final RegistrationRequest request = new RegistrationRequest();
request.setEmail(email);
request.setEmailRepeat(emailRepeat);
request.setPasswort(password);
return request;
}
}
This allows me to create an object like this:
SomeTestUtils.aRegistrationRequest()
.withEmail("[email protected]")
.withEmailRepeat("[email protected]")
.withPassword("my-password")
.withPasswordRepeat("my-password")
.build();
But now I'd like to provide default value for any field which is not explicitly set. So if I did this, then an object with all the defaults shall be created:
SomeTestUtils.aRegistrationRequest().build();
Lombok developer here:
You can't, not directly. The code needs to be syntactically valid java before lombok gets to do its thing, and there isn't a feasible way (at least, we've never managed to think of something acceptable) to write what you want in java syntax. These things all simply won't work:
/* 1 */ void foo(int param = 5) {}
/* 2 */ void foo(@DefaultValue(5) int param) {}
/* 3 */ void foo(@DefaultValue("5") int param) {}
/* 4 */ void foo(int param) {
defaultValues: {
param = 5;
}
}
@IntDefaultValue
, @StringDefaultValue
, etc, but [A] that just lets you cover primitives, strings, Class<?>
values, enums, and arrays of those types - and nothing else, and [B] that means you can only supply compile time constants. This is far too restrictive.final
to every parameter (if you're one of those, I suggest you cut that out. If you hate mutating params, add a linting or IDE rule to prevent it, and remove that clutter from your code, please). It's also easy to typo the defaultValues:
param and you get zero auto-complete help.If null
is not a sensible value for the stuff you want to provide defaults for, treat null
as "I wanted the default". Something like:
@Builder void foo(Integer x) {
if (x == null) x = 5;
// carry on with the code as normal
}
or if you prefer never mutating your params (again I implore you - sanity checks and defaulting behaviour SHOULD be applied to the parameter; failure to do so means it is way too easy to accidentally use the 'wrong' one), you can do this:
@Builder void foo(Integer paramIn) {
int param == paramIn == null ? 5 : paramIn;
// carry on as normal. Woe is you if you use paramIn.
}
I suggest you add some javadoc that explains this, of course.
If null
is a sensible option, but should not be the default, we're mostly in 'wow, that is so rare and exotic, it is no longer boilerplate' territory.