【问题标题】:Lombok @With sets inherited fields on the clone to null. How do I make it copy to work?Lombok @With 将克隆上的继承字段设置为 null。我如何让它复制工作?
【发布时间】:2021-09-22 13:09:54
【问题描述】:

我正在尝试使用 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.nameclone.age 都返回 null。允许这种构造吗?如何让它发挥作用?

【问题讨论】:

  • 这能回答你的问题吗? Lombok @Wither Inheritance (super-/sub- classes)
  • @JanRieke 谢谢。在发布这个问题后,我偶然发现了toBuilder,它完成了我所追求的,尽管不太令人满意。我猜自您回答以来情况没有改变,目前最好的选择是使用toBuilder?
  • 暂时没有变化。

标签: java lombok


【解决方案1】:

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

编译错误:

  • 您不能将int 传递给String。你打电话给.age(20),但它被定义为String age
  • id 与上述相同。
  • Person 类应该是 abstract class,而不是 class abstract
  • Person 的全参数构造函数未定义,因此Employee 无法编译。用@AllArgsConstructor 注释Person
  • 由于父类中的继承和非参数构造函数,您必须删除放置在Employee 上的@AllArgsConstructor@NoArgsConstructor

警告:

  • Lombok 需要 @With 注释在 Employee 类中的基本默认构造函数 - 您必须手动定义它:public Employee(int id)。在https://projectlombok.org/features/With 阅读@With 注释的规范。

    @With 依赖于所有字段的构造函数来完成其工作。如果此构造函数不存在,您的@With 注释将导致编译时错误消息。

修复上述所有问题后,代码开始工作。下次,请至少准备一个可编译的sn-p。

@Test
void testWith() {
    var template = Employee.builder().name("John Smith").age(20).build();
    var clone = template.withId(23);
    assertThat(clone.getId(), is(23));
}

【讨论】:

  • 我现在已经更正了示例代码。但是,即使完成了所有更正,问题仍然存在。您在测试中错过的是检查age 和/或name,而不是Employee 类中定义的id。问题是那些继承的字段在克隆后是空的。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 2019-01-15
    • 1970-01-01
    • 2015-03-28
    • 2018-11-24
    相关资源
    最近更新 更多