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

若必填字段含空值,如何终止Jackson对整个对象的序列化?

解决方案:Jackson序列化时校验必填字段并终止序列化

问题背景

现有如下结构的JSON:

{
  "field1": "value1",
  "field2": "value2",
  ...
  "field100": "value100"
}

对应的POJO定义:

@Builder
@Data
public class BigJsonDto{
    private String field1;
    private String field2;
    // ... 省略中间字段
    private String field100;
}

需求细节:

  • field1不可为空(值不能是null/空字符串)
  • 其余所有字段为必填但可为空(字段必须参与序列化,但允许值为null)
  • 序列化时,只要有一个必填字段(含field1)不符合要求(field1为空,或其他必填字段值为null),就终止整个对象的序列化,而非忽略空值输出JSON

实现方案:自定义Jackson序列化器

由于@JsonProperty(required = true)仅作用于反序列化,无法满足序列化时的校验需求,我们可以通过自定义序列化器实现前置校验逻辑:

步骤1:定义序列化必填字段的标记注解

先创建一个自定义注解,用来标记哪些字段是序列化时必须非空的(除了field1):

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SerializeRequired {
}

步骤2:修改POJO并关联序列化器

更新POJO,用自定义注解标记必填字段,并指定自定义序列化器:

@Builder
@Data
@JsonSerialize(using = BigJsonDtoSerializer.class)
public class BigJsonDto{
    // field1不可为空
    private String field1;
    
    @SerializeRequired
    private String field2;
    // ... 省略中间字段
    @SerializeRequired
    private String field100;
}

步骤3:编写自定义序列化器

实现StdSerializer,在序列化前添加校验逻辑,一旦校验失败就抛出异常终止序列化:

public class BigJsonDtoSerializer extends StdSerializer<BigJsonDto> {

    public BigJsonDtoSerializer() {
        super(BigJsonDto.class);
    }

    @Override
    public void serialize(BigJsonDto value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // 校验field1非空
        if (value.getField1() == null || value.getField1().trim().isEmpty()) {
            throw new JsonProcessingException("field1 不能为空或空白字符串") {};
        }

        // 校验所有标记@SerializeRequired的字段是否为null
        Field[] fields = BigJsonDto.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(SerializeRequired.class)) {
                field.setAccessible(true);
                try {
                    Object fieldValue = field.get(value);
                    if (fieldValue == null) {
                        throw new JsonProcessingException(String.format("必填字段 %s 不能为null", field.getName())) {};
                    }
                } catch (IllegalAccessException e) {
                    throw new JsonProcessingException("序列化校验时访问字段失败", e) {};
                }
            }
        }

        // 校验通过,执行正常序列化
        provider.defaultSerializeValue(value, gen);
    }
}

步骤4:使用ObjectMapper进行序列化

在业务代码中使用ObjectMapper,捕获序列化异常即可处理校验失败的情况:

ObjectMapper mapper = new ObjectMapper();
BigJsonDto dto = BigJsonDto.builder()
        .field1("validValue")
        .field2(null) // 故意设置为null触发校验失败
        .field100("value100")
        .build();

try {
    String json = mapper.writeValueAsString(dto);
    System.out.println("序列化结果:" + json);
} catch (JsonProcessingException e) {
    // 校验失败,终止序列化,此处可添加异常处理逻辑
    System.err.println("序列化终止:" + e.getMessage());
}

替代方案:序列化前手动校验

如果不想自定义序列化器,也可以结合Bean Validation在序列化前手动校验:

  1. 给POJO添加校验注解:
@Builder
@Data
public class BigJsonDto{
    @NotNull(message = "field1不能为空")
    @NotBlank(message = "field1不能为空白字符串")
    private String field1;
    
    @NotNull(message = "field2不能为null")
    private String field2;
    // ... 省略中间字段
    @NotNull(message = "field100不能为null")
    private String field100;
}
  1. 序列化前执行校验:
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
BigJsonDto dto = BigJsonDto.builder().field1("value1").field2(null).build();

Set<ConstraintViolation<BigJsonDto>> violations = validator.validate(dto);
if (!violations.isEmpty()) {
    // 校验失败,不执行序列化
    violations.forEach(v -> System.err.println(v.getMessage()));
} else {
    ObjectMapper mapper = new ObjectMapper();
    String json = mapper.writeValueAsString(dto);
    System.out.println(json);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:21:37