在给一个用@Builder注解的Java Bean的一个属性赋默认值之后,使用build方式构建出来的对象该属性的值是null。
本地模拟
在本地创建一个User类,给vip赋上默认值true。并写了一个测试用例,判断vip是否是null。
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
private Long id;
private Boolean vip = true;
}
@Test
public void buildTest(){
User user = User.builder().id(1L).build();
assertNull(user.getVip());
}
测试用例可以跑过,说明User的vip并没有赋默认值。这是为什么呢?打开User.class反编译之后的文件可以看到,@Builder注解的作用其实就是帮程序员免去写构造者模式的麻烦,内部生成一个UserBuilder静态内部类。当调用build函数的时候,创建对象。由于生成的代码中,没有给vip字段赋默认值自然拿到的是null。
.....省略部分代码......
public static class UserBuilder {
private Long id;
private Boolean vip;
UserBuilder() {
}
public UserBuilder id(final Long id) {
this.id = id;
return this;
}
public UserBuilder vip(final Boolean vip) {
this.vip = vip;
return this;
}
public User build() {
return new User(this.id, this.vip);
}
public String toString() {
return "User.UserBuilder(id=" + this.id + ", vip=" + this.vip + ")";
}
}
解决办法
解决办法也很简单,不需要我们重写User的建造者模式,只要在赋默认值的属性上加上@Builder.Default注解就可以了。
@Data
@Builder
public class User {
private Long id;
@Builder.Default
private Boolean vip = true;
}
再反编译User.class文件文件,发现生成了一个静态方法defaultvip(),该方法返回的就是vip的默认值。调用build方法时会判断vip是否已经设置,没有设置则调用defaultvip()方法赋值。
public class User {
private Long id;
private Boolean vip;
private static Boolean $default$vip() {
return true;
}
public static class UserBuilder {
..
public User build() {
Boolean vip$value = this.vip$value;
if (!this.vip$set) {
vip$value = User.$default$vip();
}
return new User(this.id, vip$value);
}
}
}