如何在具有最终字段的抽象类上使用 Lombok @SuperBuilder

bur*_*n16 6 java design-patterns builder lombok

给定以下带有 Lombok 注释的类@Data@SuperBuilder

@Data
@SuperBuilder
public abstract class Parent {

    protected final String userId;
    protected final Instant requestingTime;
}

@Data
@SuperBuilder
public class Child extends Parent {

    private final Instant beginningDate;
    private final Instant endingDate;
    private final Collection<String> fields;
}

Run Code Online (Sandbox Code Playgroud)

@DataChild类中的注释上出现以下错误:

隐式超级构造函数 Parent() 未定义。必须显式调用另一个构造函数。

有没有办法在Child类的@Data注释上配置非默认构造函数,以便在调用 Builder 时初始化和类final上的所有字段?ChildParent

我已经尝试了@Data, @Getter,@Setter注释与@SuperBuilder子类和父类上的注释的几种不同组合,但还没有找到可行的解决方案。我正在使用 Lombok 1.18.10。

作为参考,这个问题是相关的

编辑

这实际上是 Lombok 应该在SuperBuilder.build()操作上构造和调用的构造函数。

public Child(
    final String userId,
    final Instant requestingTime,
    final Instant beginningDate,
    final Instant endingDate,
    final Collection<String> fields) {

    super(userId, requestingTime);
    this.beginningDate = beginningDate;
    this.endingDate = endingDate;
    this.fields= fields;
}
Run Code Online (Sandbox Code Playgroud)

根据要求,这就是我期望在Child对象上调用构建器的方式。

final Child child = Child.Builder()
                         .userId(<value>)
                         .requestingTime(<value>)
                         .beginningDate(<value>)
                         .endingDate(<value>)
                         .fields(<value>)
                         .build();
Run Code Online (Sandbox Code Playgroud)

maa*_*nus 5

AFAIK,@Data生成一个@NoArgsConstructor,这是错误的。实际上,@Data它本身就是错误的,因为它适用于可变类;@Value会更好,但它也不能处理超级构造函数。

因此,删除@Data、添加@Getter@EqualsAndHashCode以及@ToString任何您需要的内容。不要忘记添加callSuper=true子类。


这实际上是 Lombok 应该在 SuperBuilder.build() 操作上构建和调用的构造函数。

public Child(
    final String userId,
    final Instant requestingTime,
    final Instant beginningDate,
    final Instant endingDate,
    final Collection<String> fields) {

    super(userId, requestingTime);
    this.beginningDate = beginningDate;
    this.endingDate = endingDate;
    this.fields= fields;
}
Run Code Online (Sandbox Code Playgroud)

不,事情不是这样的SuperBuilder。这实际上是 Lombok 无法做到的,因为它看不到超级字段。相反,构建器使用类似的东西

public Child(ChildBuilder b) {    
    super(b);
    this.beginningDate = b.beginningDate;
    this.endingDate = b.endingDate;
    this.fields= b.fields;
}
Run Code Online (Sandbox Code Playgroud)

你可以相信 Jan Rieke 说的话,他写的。

  • `@SuperBuilder` 使用它自己的特殊构造函数,它只接受一个构建器实例作为参数。无需定义任何其他内容。我刚刚验证了删除“@Data”后您的代码可以正常编译。 (2认同)