在方法级别使用 Lombok @Builder 时提供默认值?
Provide default values when using Lombok @Builder on method level?
假设有以下示例性 class 不受我的控制,即我无法更改其行为。
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class RegistrationRequest {
private String email;
private String emailRepeat;
private String password;
private String passwordRepeat;
}
我想使用 Lombok @Builder
为这个 class 构建测试数据,所以我将 @Builder
注释放在方法级别,如下所示:
public class SomeTestUtils {
public static final String DEFAULT_EMAIL = "foo@bar.com";
public static final String DEFAULT_EMAIL_REPEAT = "foo@bar.com";
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;
}
}
这让我可以创建这样的对象:
SomeTestUtils.aRegistrationRequest()
.withEmail("foo@bar.com")
.withEmailRepeat("foo@bar.com")
.withPassword("my-password")
.withPasswordRepeat("my-password")
.build();
但现在我想为任何未明确设置的字段提供默认值。所以如果我这样做,那么将创建一个具有所有默认值的对象:
SomeTestUtils.aRegistrationRequest().build();
这里是 Lombok 开发者:
你不能,不能直接。在 lombok 开始做它的事情之前,代码需要在语法上有效 java,并且没有可行的方法(至少,我们从来没有想过可以接受的东西)来写你想要的东西 java语法。这些东西根本行不通:
/* 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;
}
}
- 这甚至无法解析。 Javac 因语法错误而失败,甚至没有调用 lombok。我们不能这样做。
- 注释参数需要特定类型 - 您不能定义采用类型为 'whatever' 的参数的注释。我们可以制作
@IntDefaultValue
、@StringDefaultValue
等,但是 [A] 只允许您涵盖基元、字符串、Class<?>
值、枚举和这些类型的数组——除此之外别无其他,并且[B] 这意味着您只能提供编译时常量。这限制太多了。
- 这会 'work' 但是在字符串文字中推送实际的 java 代码太丑陋了,我们不会将其添加到 lombok。
- 这是最接近可行的,但是您不可能记住您必须完全按照那样来编写它,而且 linting 工具会对此感到相当困惑。它还与许多 java 程序员向每个参数添加
final
的烦人习惯发生冲突(如果你是其中之一,我建议你把它剪掉。如果你讨厌改变参数,添加一个 linting或 IDE 规则来防止它,请从您的代码中删除该混乱)。 defaultValues:
参数也很容易打错,你会得到零个自动完成帮助。
好的,那我该怎么做呢?
如果 null
不是您要为其提供默认值的内容的合理值,请将 null
视为“我想要默认值”。类似于:
@Builder void foo(Integer x) {
if (x == null) x = 5;
// carry on with the code as normal
}
或者如果你不想改变你的参数(我再次恳求你 - 健全性检查和默认行为应该应用于参数;不这样做意味着很容易不小心使用 'wrong'一),你可以这样做:
@Builder void foo(Integer paramIn) {
int param == paramIn == null ? 5 : paramIn;
// carry on as normal. Woe is you if you use paramIn.
}
当然,我建议您添加一些 java文档来解释这一点。
如果 null
是一个明智的选择,但不应该是默认选项,那么我们主要在 'wow, that is so rare and exotic, it is no longer boilerplate' 范围内。
假设有以下示例性 class 不受我的控制,即我无法更改其行为。
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class RegistrationRequest {
private String email;
private String emailRepeat;
private String password;
private String passwordRepeat;
}
我想使用 Lombok @Builder
为这个 class 构建测试数据,所以我将 @Builder
注释放在方法级别,如下所示:
public class SomeTestUtils {
public static final String DEFAULT_EMAIL = "foo@bar.com";
public static final String DEFAULT_EMAIL_REPEAT = "foo@bar.com";
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;
}
}
这让我可以创建这样的对象:
SomeTestUtils.aRegistrationRequest()
.withEmail("foo@bar.com")
.withEmailRepeat("foo@bar.com")
.withPassword("my-password")
.withPasswordRepeat("my-password")
.build();
但现在我想为任何未明确设置的字段提供默认值。所以如果我这样做,那么将创建一个具有所有默认值的对象:
SomeTestUtils.aRegistrationRequest().build();
这里是 Lombok 开发者:
你不能,不能直接。在 lombok 开始做它的事情之前,代码需要在语法上有效 java,并且没有可行的方法(至少,我们从来没有想过可以接受的东西)来写你想要的东西 java语法。这些东西根本行不通:
/* 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;
}
}
- 这甚至无法解析。 Javac 因语法错误而失败,甚至没有调用 lombok。我们不能这样做。
- 注释参数需要特定类型 - 您不能定义采用类型为 'whatever' 的参数的注释。我们可以制作
@IntDefaultValue
、@StringDefaultValue
等,但是 [A] 只允许您涵盖基元、字符串、Class<?>
值、枚举和这些类型的数组——除此之外别无其他,并且[B] 这意味着您只能提供编译时常量。这限制太多了。 - 这会 'work' 但是在字符串文字中推送实际的 java 代码太丑陋了,我们不会将其添加到 lombok。
- 这是最接近可行的,但是您不可能记住您必须完全按照那样来编写它,而且 linting 工具会对此感到相当困惑。它还与许多 java 程序员向每个参数添加
final
的烦人习惯发生冲突(如果你是其中之一,我建议你把它剪掉。如果你讨厌改变参数,添加一个 linting或 IDE 规则来防止它,请从您的代码中删除该混乱)。defaultValues:
参数也很容易打错,你会得到零个自动完成帮助。
好的,那我该怎么做呢?
如果 null
不是您要为其提供默认值的内容的合理值,请将 null
视为“我想要默认值”。类似于:
@Builder void foo(Integer x) {
if (x == null) x = 5;
// carry on with the code as normal
}
或者如果你不想改变你的参数(我再次恳求你 - 健全性检查和默认行为应该应用于参数;不这样做意味着很容易不小心使用 'wrong'一),你可以这样做:
@Builder void foo(Integer paramIn) {
int param == paramIn == null ? 5 : paramIn;
// carry on as normal. Woe is you if you use paramIn.
}
当然,我建议您添加一些 java文档来解释这一点。
如果 null
是一个明智的选择,但不应该是默认选项,那么我们主要在 'wow, that is so rare and exotic, it is no longer boilerplate' 范围内。