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

如何仅配置Jackson将各类非存在List反序列化为空List?

问题:Jackson配置实现List类型缺失/Null时反序列化为空List(不修改实体类)

需求

将所有场景下的非有效List(包括JSON中字段缺失、值为Null、根对象为Null等情况)反序列化为空List,要求不可修改实体类,仅通过配置ObjectMapper实现。

测试代码

用于验证的测试类如下:

class EmptyListDeserializerTest {

    final ObjectMapper objectMapper = new ObjectMapper();

    // 此处为待调整的ObjectMapper配置

    @Test
    void test2() throws JsonProcessingException {
        // 测试根对象为Null的场景
        final var result = objectMapper.readValue("null", new TypeReference<List<MyClass>>() {});
        assertThat(result).isEmpty();
    }

    @Test
    void test3() throws JsonProcessingException {
        // 测试实体类中List字段值为Null的场景
        final var json = """
                [{
                   "name": "John Doe",
                   "address": null
                 }]
                """;
        final var result = objectMapper.readValue(json, new TypeReference<List<MyComplexClass>>() {});
        assertThat(result.get(0).address).isEmpty();
    }

    @Test
    void test4() throws JsonProcessingException {
        // 测试实体类中List字段缺失的场景
        final var json = """
                [{
                   "name": "John Doe"
                 }]
                """;
        final var result = objectMapper.readValue(json, new TypeReference<List<MyComplexClass>>() {});
        assertThat(result.get(0).address).isEmpty();
    }

    public static class MyClass {
        public MyClass() {}
        private String name;
        public MyClass(final String name) { this.name = name; }
        public String getName() { return name; }
        public void setName(final String name) { this.name = name; }
    }

    public static class MyComplexClass {
        public MyComplexClass() {}
        private String name;
        private List<String> address;
        public MyComplexClass(final String name, final List<String> address) {
            this.name = name;
            this.address = address;
        }
        public String getName() { return name; }
        public void setName(final String name) { this.name = name; }
        public List<String> getAddress() { return address; }
        public void setAddress(final List<String> address) { this.address = address; }
    }
}

当前遇到的问题

  1. 仅配置configOverride(List.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY, Nulls.AS_EMPTY))时,只有test3通过,test2(根对象Null)和test4(字段缺失)均失败。
  2. 添加自定义List反序列化器并修改test2输入为带引号的"\"null\""后,test2通过但test3失败,且自定义反序列化器的泛型处理存在问题。

问题分析

  • 初始配置仅处理了字段值为Null的场景,未覆盖字段缺失和根对象为Null的情况。
  • 自定义反序列化器直接替换了List的默认反序列化逻辑,破坏了泛型类型的正确处理,导致test3中address字段无法正确反序列化为List<String>。

正确配置方案

通过以下配置同时覆盖所有场景,无需修改实体类:

final ObjectMapper objectMapper = new ObjectMapper();

{
    // 配置List类型的setter规则:Null值、缺失字段均转为空List
    objectMapper.configOverride(List.class)
            .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)
                    .withSetterNulls(Nulls.AS_EMPTY)
                    .withMissingSetter(Nulls.AS_EMPTY));
    
    // 配置根对象为Null时返回空List,同时保留原有泛型反序列化逻辑
    objectMapper.registerModule(new SimpleModule() {
        @Override
        public void setupModule(SetupContext context) {
            context.addBeanDeserializerModifier(new BeanDeserializerModifier() {
                @Override
                public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                    if (List.class.isAssignableFrom(beanDesc.getBeanClass())) {
                        return new JsonDeserializer<>() {
                            @Override
                            public List<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                                if (p.getCurrentToken() == JsonToken.VALUE_NULL) {
                                    return Collections.emptyList();
                                }
                                // 委托原有反序列化器处理正常List,保留泛型支持
                                return (List<?>) deserializer.deserialize(p, ctxt);
                            }
                        };
                    }
                    return deserializer;
                }
            });
        }
    });
}

配置说明

  1. configOverride部分:

    • forValueNulls(Nulls.AS_EMPTY):处理JSON中字段值为Null的场景(对应test3)。
    • withMissingSetter(Nulls.AS_EMPTY):处理JSON中字段缺失的场景(对应test4)。
    • withSetterNulls(Nulls.AS_EMPTY):确保当setter接收Null值时自动转为空List。
  2. BeanDeserializerModifier部分:

    • 仅针对List类型的根对象,当JSON输入为Null时返回空List(对应test2)。
    • 委托原有反序列化器处理正常List结构,避免破坏泛型类型的解析。

测试修正

将之前错误修改的test2恢复为原始输入(反序列化JSON Null而非字符串"null"):

@Test
void test2() throws JsonProcessingException {
    final var result = objectMapper.readValue("null", new TypeReference<List<MyClass>>() {});
    assertThat(result).isEmpty();
}

此时三个测试用例均可正常通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:12:08