lombok 1.6.22 版本是唯一会额外生成私有构造函数版本,升级时需要留意是否有地方用到,比如 fastjson !!
问题
先说问题,突然线上报错:
com.alibaba.fastjson.JSONException: default constructor not found.
样例类:
@Data
@Builder
public class User {
private String name;
private int age;
}
what ? 怎么好端端的,没有构造方法了?用了 lombok 注解,自测没问题,很诡异。想到最近升级过 lombok 版本,由 ,所以可能于此有关。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<!--<version>1.16.22</version> 之前的版本-->
</dependency>
结论
这里我提了个 issue 共建者给出了解答
@Data & @Builder 1.18.22 default constructor not found #3168
如果你仍然需要生成 private constructor 需要配置
lombok.noArgsConstructor.extraPrivate = true.
1.6.22 版本在升级时需要留意,如升级请确认升级后类构建后代码一致,使用 @Builder 时建议注解组合
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
对具体复现流程,和原因感兴趣的同学可以继续往下看
验证流程
版本 1.16.22 生成
public class User {
private String name;
private int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
public static User.UserBuilder builder() {
return new User.UserBuilder();
}
private User() {
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
return this.getAge() == other.getAge();
}
} else if (this$name.equals(other$name)) {
return this.getAge() == other.getAge();
}
return false;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
result = result * 59 + this.getAge();
return result;
}
public String toString() {
return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";
}
public static class UserBuilder {
private String name;
private int age;
UserBuilder() {
}
public User.UserBuilder name(String name) {
this.name = name;
return this;
}
public User.UserBuilder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(this.name, this.age);
}
public String toString() {
return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ")";
}
}
}
版本 1.18.22 生成
public class User {
private String name;
private int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
public static User.UserBuilder builder() {
return new User.UserBuilder();
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof User)) {
return false;
} else {
User other = (User)o;
if (!other.canEqual(this)) {
return false;
} else if (this.getAge() != other.getAge()) {
return false;
} else {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name != null) {
return false;
}
} else if (!this$name.equals(other$name)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof User;
}
public int hashCode() {
int PRIME = true;
int result = 1;
int result = result * 59 + this.getAge();
Object $name = this.getName();
result = result * 59 + ($name == null ? 43 : $name.hashCode());
return result;
}
public String toString() {
return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";
}
public static class UserBuilder {
private String name;
private int age;
UserBuilder() {
}
public User.UserBuilder name(String name) {
this.name = name;
return this;
}
public User.UserBuilder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(this.name, this.age);
}
public String toString() {
return "User.UserBuilder(name=" + this.name + ", age=" + this.age + ")";
}
}
}
看一下对比,少了一个 private 的默认构造函数。
这会导致什么问题?比如我们常用的 fastjson
public class TestJsonFormat {
public static void main(String[] args) {
String userString="{\"age\":20,\"name\":\"dyinggq\"}";
User user = JSONObject.parseObject(userString, User.class);
System.out.println(user);
}
}
在没有默认构造函数的情况下解析时会报错。而对于 1.16.22 版本生成私有默认构造函数
public class JavaBeanInfo {
// 获取默认构造函数
Constructor<?> defaultConstructor = null;
if ((!kotlin) || constructors.length == 1) {
if (builderClass == null) {
defaultConstructor = getDefaultConstructor(clazz, constructors);
} else {
defaultConstructor = getDefaultConstructor(builderClass, builderClass.getDeclaredConstructors());
}
}
// 如果默认构造不可访问设置可访问
if (defaultConstructor != null) {
TypeUtils.setAccessible(defaultConstructor);
}
}