[英]Default value in lombok. How to init default with both constructor and builder
I have an object我有一个对象
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private int id;
private String nick;
private boolean isEmailConfirmed = true;
}
And I initialize it in two ways我用两种方式初始化它
UserInfo ui = new UserInfo();
UserInfo ui2 = UserInfo.builder().build();
System.out.println("ui: " + ui.isEmailConfirmed());
System.out.println("ui2: " + ui2.isEmailConfirmed());
Here is output这是输出
ui: true
ui2: false
It seems that builder does not get a default value.似乎 builder 没有获得默认值。 I add
@Builder.Default
annotation to my property and my object now looks like this我将
@Builder.Default
注释添加到我的属性中,我的对象现在看起来像这样
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private int id;
private String nick;
@Builder.Default
private boolean isEmailConfirmed = true;
}
Here is console output这是控制台输出
ui: false
ui2: true
How can I make them both be true
?我怎样才能让它们都是
true
?
My guess is that it's not possible (without having delomboked the code).我的猜测是这是不可能的(没有对代码进行 delomboked)。 But why don't you just implement the constructor you need?
但是你为什么不实现你需要的构造函数呢? Lombok is meant to make your life easier, and if something won't work with Lombok, just do it the old fashioned way.
Lombok 旨在让您的生活更轻松,如果 Lombok 无法解决某些问题,请按照老式方法进行操作。
@Data
@Builder
@AllArgsConstructor
public class UserInfo {
private int id;
private String nick;
@Builder.Default
private boolean isEmailConfirmed = true;
public UserInfo(){
isEmailConfirmed = true;
}
}
Console output:控制台输出:
ui: true
ui2: true
Update更新
As of 01/2021, this bug seems to be fixed in Lombok , at least for generated constructors.截至 01/2021,此错误似乎已在 Lombok 中修复,至少对于生成的构造函数而言。 Note that there is still a similar issue when you mix
Builder.Default
and explicit constructors.请注意,当您混合使用
Builder.Default
和显式构造函数时,仍然存在类似的问题。
Since the @Builder.Default
annotation is broken , I wouldn't use it at all.由于
@Builder.Default
注释已损坏,我根本不会使用它。 You can, however, use the following approach by moving the @Builder
annotation from class level to the custom constructor:但是,您可以通过将
@Builder
注释从类级别移动到自定义构造函数来使用以下方法:
@Data
@NoArgsConstructor
public class UserInfo {
private int id;
private String nick;
private boolean isEmailConfirmed = true;
@Builder
@SuppressWarnings("unused")
private UserInfo(int id, String nick, Boolean isEmailConfirmed) {
this.id = id;
this.nick = nick;
this.isEmailConfirmed = Optional.ofNullable(isEmailConfirmed).orElse(this.isEmailConfirmed);
}
}
This way you ensure:这样您可以确保:
isEmailConfirmed
is initialized only in one place making the code less error-prone and easier to maintain laterisEmailConfirmed
仅在一处初始化,从而使代码不易出错isEmailConfirmed
易于以后维护UserInfo
class will be initialized the same way either you use a builder or a no-args constructor UserInfo
类将以与使用构建器或无参数构造函数相同的方式初始化In other words, the condition holds true
:换句话说,该条件成立
true
:
new UserInfo().equals(UserInfo.builder().build())
In that case, the object creation is consistent no matter how you create it.在这种情况下,无论您如何创建对象,对象创建都是一致的。 It is especially important when your class is used by a mapping framework or by JPA provider when you are not instantiating it manually by a builder but a no-args constructor is invoked behind your back to create the instance.
当您的类被映射框架或 JPA 提供者使用时,当您不是由构建器手动实例化它,而是在背后调用无参数构造函数来创建实例时,这一点尤其重要。
The approach described above is very similar but it has a major drawback.该方法上面描述的非常相似,但它有一个很大的缺点。 You have to initialize the field in two places which makes the code error-prone as you are required to keep the values consistent.
您必须在两个地方初始化该字段,这会使代码容易出错,因为您需要保持值一致。
Another way is define your own getter method overriding the lombok getter:另一种方法是定义自己的getter方法来覆盖lombok getter:
@Data
@Builder
@AllArgsConstructor
public class UserInfo {
private int id;
private String nick;
private Boolean isEmailConfirmed;
public Boolean getIsEmailConfirmed(){
return Objects.isNull(isEmailConfirmed) ? true : isEmailConfirmed;
}
}
My experience is that @Builder
works best when it is the only means of instantiating a class, and therefore works best when paired with @Value
rather than @Data
.我的经验是
@Builder
在它是实例化类的唯一方法时效果最好,因此在与@Value
而不是@Data
配对时效果最好。
For classes where all fields are mutable in any order anyway, and for which you want to keep the chained calls, consider replacing it with @Accessors(chain=true)
or @Accessors(fluent=true)
.对于所有字段以任何顺序可变的类,并且您希望保留链接调用,请考虑将其替换为
@Accessors(chain=true)
或@Accessors(fluent=true)
。
@Data
@Accessors(fluent=true)
public class UserInfo {
private int id;
private String nick;
private boolean isEmailConfirmed = true;
}
This allows you to construct your objects fluently in the code, and avoid un-necessary creation of Builder objects:这允许您在代码中流畅地构建对象,并避免不必要地创建 Builder 对象:
UserInfo ui = new UserInfo().id(25).nick("John");
Here's my approach :这是我的方法:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class UserInfo {
private int id;
private String nick;
private boolean isEmailConfirmed = true;
}
And then接着
UserInfo ui = new UserInfo().toBuilder().build();
In version 1.18.2 both @NoArgsConstructor
and @Builder
work, but not completely.在 1.18.2 版本中,
@NoArgsConstructor
和@Builder
工作,但不完全。
Constructor with one or more fields will null all other default initialisations: new UserInfo("Some nick")
will cause isEmailConfirmed
to be false again.具有一个或多个字段的构造函数将使所有其他默认初始化为空:
new UserInfo("Some nick")
将导致isEmailConfirmed
再次为 false。
My way to handle this is:我的处理方法是:
public UserInfo(String nick) {
this();
this.nick = nick;
}
This way all default fields will be initialised and we'll get expected constructor.这样所有默认字段都将被初始化,我们将获得预期的构造函数。
Initialize the properties in the No-Arg Constructor
初始化 No-Arg
Constructor
的属性
converted转换
private boolean isEmailConfirmed = true;
to到
public class UserInfo {
public UserInfo() {
this.isEmailConfirmed = true;
}
}
You can create a static Builder class with default values populated:您可以创建一个静态 Builder 类,并填充默认值:
@Data
@Builder(builderClassName="Builder")
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
private int id;
private String nick;
private boolean isEmailConfirmed;
public static class Builder{
//Set defaults here
private boolean isEmailConfirmed = true;
}
}
Custom constructors and @Builder.Default
probably will never work together.自定义构造函数和
@Builder.Default
可能永远不会一起工作。
Framework authors want to avoid double initializations for @Builder
.框架作者希望避免对
@Builder
进行双重初始化。
I reuse .builder()
by public static CLAZZ of(...)
methods:我通过
public static CLAZZ of(...)
方法重用.builder()
:
@Builder
public class Connection {
private String user;
private String pass;
@Builder.Default
private long timeout = 10_000;
@Builder.Default
private String port = "8080";
public static Connection of(String user, String pass) {
return Connection.builder()
.user(user)
.pass(pass)
.build();
}
public static Connection of(String user, String pass, String port) {
return Connection.builder()
.user(user)
.pass(pass)
.port(port)
.build();
}
public static Connection of(String user, String pass, String port, long timeout) {
return Connection.builder()
.user(user)
.pass(pass)
.port(port)
.timeout(timeout)
.build();
}
}
Check corresponding discussion: https://github.com/rzwitserloot/lombok/issues/1347查看对应讨论: https : //github.com/rzwitserloot/lombok/issues/1347
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.