返回

Java Record 局部更新难题:揭秘 Jackson 优雅解法

java

Java Record 局部更新:用 Jackson 实现的优雅解决方案

简介

当使用 Java Record 处理 Web 请求中的局部更新时,区分 null 值(表示将字段更新为 null)和已省略字段(表示保持字段不变)至关重要。为了避免在 DTO 中使用 Optional 或 Map,我们可以利用 Jackson 反序列化库自定义反序列化过程。

问题:区分 null 值和已省略字段

Java Record 的不可变性要求明确设置字段值。但是,传入的 JSON 请求可能包含 null 值(表示需要更新)或已省略字段(表示不变)。

解决方案:自定义反序列化器

通过创建一个自定义反序列化器,我们可以将 JSON 中的 null 值转换为 Java Record 字段的 Optional.empty(),而将已省略字段转换为 Optional.of(null)。

优势:

  • 保持 Java Record 的不可变性。
  • 避免在 DTO 中使用 Optional 或 Map。
  • 提供灵活的自定义,以满足复杂场景。

实现步骤:

  1. 创建自定义反序列化器:

    import com.fasterxml.jackson.core.JsonParser;
    // ...
    public class JavaRecordDeserializer extends JsonDeserializer<JavaRecord> {
        // ...
    }
    
  2. 注册反序列化器:

    import org.springframework.context.annotation.Bean;
    import org.springframework.web.reactive.config.WebFluxConfigurer;
    // ...
    public class WebFluxConfig implements WebFluxConfigurer {
        // ...
    }
    

示例:

import com.fasterxml.jackson.core.JsonParser;
// ...
public class JavaRecordDeserializer extends JsonDeserializer<JavaRecord> {
    @Override
    public JavaRecord deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        // ...
        if (token == JsonToken.VALUE_NULL) {
            values[index] = Optional.empty();
        } else {
            values[index] = Optional.of(parser.readValueAs(nonStaticFields.get(index).getType()));
        }
        // ...
        return new JavaRecord(values);
    }
}

结论

使用自定义反序列化器,我们可以优雅地处理 Java Record 的局部更新,区分 null 值和已省略字段,从而保持类型安全、数据不可变性和自定义灵活性。

常见问题解答:

  1. 为什么不使用 Optional?
    为了避免序列化/反序列化上下文中 Optional 的问题。

  2. 为什么不使用 Map?
    为了确保类型安全。

  3. 自定义反序列化器如何工作?
    它遍历 JSON 请求并根据 token(null 或非 null)将字段转换为 Optional.empty() 或 Optional.of(null)。

  4. 在哪里注册自定义反序列化器?
    在 Spring WebFlux WebFluxConfig 类中。

  5. 有什么优势?
    Java Record 的类型安全、数据不可变性和自定义灵活性。