我正在尝试使用 Lombok 的
@With
注释来设置克隆,但我遇到了一个问题,它将继承的字段设置为 null。为了进行演示,假设我有以下类层次结构:
@NoArgsConstructor
@AllArgsConstructor
@Getter
abstract class Person {
protected String name;
protected Integer age;
}
@NoArgsConstructor
@AllArgsConstructor
@With
@Getter
class Employee extends Person {
protected String id;
@Builder
public Employee(String name, Integer age, String id) {
super(name, age);
this.id = id;
}
}
当我尝试这样做时:
var template = Employee.builder().name("John Smith").age(20).build();
var clone = template.withId("ABC123");
clone.name
和 clone.age
都返回 null。允许这种构造吗?我该如何让它发挥作用?
我无法使用您的代码进行重现,因为它是错误的,请修复以下错误,然后您的代码即可正常工作:
编译错误:
int
传递给 String
。您调用 .age(20)
但它被定义为 String age
。id
完全相同。Person
类应该是 abstract class
,而不是 class abstract
。Person
的全参数构造函数未定义,因此Employee
无法编译。用 Person
注释 @AllArgsConstructor
。@AllArgsConstructor
和放在@NoArgsConstructor
上的Employee
。警告:
Lombok 需要
@With
注释在 Employee
类中使用基本默认构造函数 - 您必须手动定义它:public Employee(int id)
。请阅读 @With
注释的规范,网址为 https://projectlombok.org/features/With。
依赖于所有字段的构造函数来完成其工作。如果此构造函数不存在,您的@With
注释将导致编译时错误消息。@With
修复上述所有问题后,代码开始运行。下次,请至少准备一个可编译的片段。
@Test
void testWith() {
var template = Employee.builder().name("John Smith").age(20).build();
var clone = template.withId(23);
assertThat(clone.getId(), is(23));
}
@With 似乎不适用于继承。 作为解决方法,您可以尝试以下代码:
@NoArgsConstructor
@AllArgsConstructor
@Getter
abstract class Person {
protected String name;
protected Integer age;
}
@Getter
@AllArgsConstructor
class Employee extends Person {
protected String id;
@Builder
public Employee(String name, Integer age, String id) {
super(name, age);
this.id = id;
}
public Employee withId(String id) {
return this.id == id ? this : new Employee(name, age, id);
}
}
它会起作用,但不幸的是,你必须自己实现“withId”方法。
Lombok @With 不支持继承字段。 不管是谁,我确实找到了在两个类上使用
@SuperBuilder(toBuilder = true)
注释的可行解决方法。这样,就不用调用 someInstance.withSomeField(xyz)
方法,
你称其为someInstance.toBuilder().someField(xyz).build()
。
这确实保留了所有基类字段并创建了一个新实例。虽然更长,但它看起来仍然非常清晰且具有自文档化的代码。
考虑这个例子:
@Data
@SuperBuilder(toBuilder = true)
public static class Animal {
String color;
}
@Data
@SuperBuilder(toBuilder = true)
public static class Cat extends Animal {
String name;
}
现在你可以像这样调用toBuilder:
Cat catKoko = Cat.builder().name("Koko").color("mixed").build(); //name=Koko , color=mixed
Cat catLolik = catKoko.toBuilder().name("Lolik").build(); //name=Lolik , color=mixed