
本文介绍如何在使用 Lombok @Builder 时,对枚举字段(如 TestEnum)施加运行时校验(仅允许 ALPHA 或 BETA),无需手写完整 Builder,而是通过局部方法覆盖 + 条件抛异常实现轻量、安全、可维护的约束控制。
本文介绍如何在使用 lombok `@builder` 时,对枚举字段(如 `testenum`)施加运行时校验(仅允许 `alpha` 或 `beta`),无需手写完整 builder,而是通过局部方法覆盖 + 条件抛异常实现轻量、安全、可维护的约束控制。
在基于 Lombok 的构建器模式开发中,@Builder 能显著减少样板代码,但其内置注解(如 @NonNull)仅支持空值检查,无法满足枚举值范围校验这类业务约束需求。例如,当 TestEnum 包含 ALPHA、BETA、GAMMA 三个常量,而业务逻辑严格要求 test 字段只能为前两者时,就需要额外干预。
✅ 推荐方案:局部覆盖 Builder 方法(推荐用于 Builder 场景)
最简洁且侵入性最小的方式是——仅重写 Builder 中对应字段的 setter 方法,保留 Lombok 自动生成的其余逻辑:
@Builder(toBuilder = true)
public class Testing {
@NonNull private String id;
@NonNull private TestEnum test;
private String message;
// 手动定义 Builder 内部类中的 test() 方法,加入业务校验
public static class TestingBuilder {
public TestingBuilder test(@NonNull TestEnum test) {
if (test != TestEnum.ALPHA && test != TestEnum.BETA) {
throw new IllegalArgumentException("test can only be ALPHA or BETA!");
}
this.test = test;
return this;
}
}
}
? 关键说明:
- 类名
TestingBuilder和方法名test必须与 Lombok 默认生成的一致(可通过javap -c Testing$TestingBuilder验证);- 此方式仅影响通过 Builder 创建实例的路径,不影响直接调用构造函数的场景;
@NonNull注解仍生效,确保传入非 null,再由自定义逻辑进一步校验取值范围。
✅ 进阶方案:强制全路径校验(推荐用于领域强一致性场景)
若需保证任何创建 Testing 实例的方式(包括反射、序列化反解析、手动 new 等)均无法绕过该约束,则应放弃依赖 Builder 校验,转而自定义私有/包级构造函数 + 公共静态工厂方法:
public class Testing {
@NonNull private final String id;
@NonNull private final TestEnum test;
private final String message;
// 私有构造函数,封装核心校验逻辑
private Testing(@NonNull String id, @NonNull TestEnum test, String message) {
if (test != TestEnum.ALPHA && test != TestEnum.BETA) {
throw new IllegalArgumentException("test can only be ALPHA or BETA!");
}
this.id = id;
this.test = test;
this.message = message;
}
// 对外提供类型安全的 Builder(可选:配合 @Builder(builderMethodName = "") 禁用默认 Builder)
public static TestingBuilder builder() {
return new TestingBuilder();
}
public static class TestingBuilder {
private String id;
private TestEnum test;
private String message;
public TestingBuilder id(@NonNull String id) { this.id = id; return this; }
public TestingBuilder test(@NonNull TestEnum test) {
if (test != TestEnum.ALPHA && test != TestEnum.BETA) {
throw new IllegalArgumentException("test can only be ALPHA or BETA!");
}
this.test = test;
return this;
}
public TestingBuilder message(String message) { this.message = message; return this; }
public Testing build() {
return new Testing(id, test, message);
}
}
}
⚠️ 注意事项与最佳实践
- ❌ 不要尝试为
TestEnum自定义 JSR-303 注解(如@ValidEnum(values = {ALPHA, BETA}))并期望 Lombok Builder 自动识别——Lombok 不解析或执行任意第三方校验注解; - ✅ 若项目已引入 Jakarta Validation(如 Hibernate Validator),可将校验逻辑移至
@Valid+ConstraintValidator,但需配合手动调用Validator.validate(),无法与 Builder 自动集成; - ✅ 建议将枚举约束逻辑抽取为静态工具方法(如
TestEnum.requireAlphaOrBeta(TestEnum)),提升复用性与可测性; - ✅ 在单元测试中务必覆盖非法值场景(如
GAMMA),验证异常是否如期抛出。
综上,针对 Lombok Builder 下的枚举范围校验,局部覆盖 Builder 方法是最简、高效、符合“约定优于配置”原则的实践方案;而当领域模型要求绝对不可变约束时,则应以构造函数为中心重构初始化逻辑,从根本上保障数据完整性。










