Lombok @With 将克隆上的继承字段设置为 null。我如何让它复制工作?

问题描述 投票:0回答:3

我正在尝试使用 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。允许这种构造吗?我该如何让它发挥作用?

java lombok
3个回答
0
投票

我无法使用您的代码进行重现,因为它是错误的,请修复以下错误,然后您的代码即可正常工作:

编译错误:

  • 您无法将
    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));
}

0
投票

@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”方法。


0
投票

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
    
© www.soinside.com 2019 - 2024. All rights reserved.