You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多层继承下含必填字段的类使用Lombok @Builder报错如何解决

问题根因
  • 放在类上的@Builder默认只会为当前类声明的字段生成全参构造:你当前类只有int myOptField1、String myOptField2两个字段,所以Lombok自动生成的全参构造签名为MyException(int, String)。这个构造没有显式调用父类Exception的有参构造,默认会尝试调用父类无参构造,而Exception没有无参构造,本身就存在编译问题。
  • 你自定义的builder(String, Throwable)方法虽然先实例化了带父类参数的对象,但调用toBuilder()后最终执行build()时,仍然会调用Lombok生成的参数不匹配的全参构造,所以触发报错。
  • 类上的@Builder默认不会处理父类的message、cause字段,就算编译通过,最终生成的异常对象也会丢失这两个必填参数的值。

IntelliJ IDEA无报错是因为Lombok插件的预校验逻辑和真实编译逻辑存在差异,插件识别到了你自定义的构造和Builder方法,但实际编译时Lombok注解处理器生成的构造方法参数不匹配才会暴露问题。

解决方案

方案1:将@Builder放在自定义的全参构造上(推荐,适合父类不可修改的场景)

这种方式让Lombok基于你指定的构造生成Builder,同时兼容父类必填参数和自定义可选字段,无需修改父类代码:

@Getter
public class MyException extends Exception {

    private int    myOptField1;
    private String myOptField2;

    // 把@Builder放在自定义的全参构造上,显式包含必填父类参数和自定义可选字段
    @Builder(toBuilder = true)
    public MyException(String message, Throwable cause, int myOptField1, String myOptField2) {
        super(message, cause);
        this.myOptField1 = myOptField1;
        this.myOptField2 = myOptField2;
    }

    // 自定义带必填参数的builder入口,强制要求传入必填字段,可选字段留默认初始值
    public static MyExceptionBuilder builder(String message, Throwable cause) {
        return new MyException(message, cause, 0, null).toBuilder();
    }
}

使用方式和你原有代码完全一致,无使用侧改造:

MyException
    .builder("Mandatory message", new SpecificException("specificCause"))
    .myOptField2("value")
    .build();

方案优势

  • 所有构造逻辑都走你自己实现的构造方法,保证message、cause能正确传给父类构造,不会丢失
  • Lombok生成的Builder参数完全匹配,不会出现参数长度不匹配的编译报错
  • 保留了toBuilder能力,同时维持了必填参数的强校验,必须传入message和cause才能调用builder入口

方案2:用@SuperBuilder处理继承场景(仅适合父类可修改的多层继承场景)

如果你的继承层级较深且所有父类都可以修改注解,可以用@SuperBuilder自动处理父类字段,无需手动写全参构造:

@SuperBuilder(toBuilder = true)
@Getter
public class MyException extends Exception {
    private int    myOptField1;
    private String myOptField2;

    public MyException(String message, Throwable cause) {
        super(message, cause);
    }

    // 自定义必填参数入口
    public static MyExceptionBuilder<?, ?> builder(String message, Throwable cause) {
        return MyException.builder()
                .message(message)
                .cause(cause);
    }
}

注意:该方案要求所有父类都添加@SuperBuilder注解,父类为不可修改的JDK原生类时不可用。

内容的提问来源于stack exchange,提问作者Radek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 12:57:04