多层继承下含必填字段的类使用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
相关产品推荐
相关产品推荐

