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

如何使用Jackson将空JSON数组反序列化为空TreeMap<String, MyOtherClass>对象

解决方案

问题根源

Jackson默认不支持将JSON数组类型直接反序列化为Java Map类型,哪怕是空数组也会触发类型不匹配异常,这就是你看到MismatchedInputException的核心原因。你之前的尝试存在两处问题:开启ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT只会将空数组转为null,无法得到你需要的空TreeMap;你写的setOtherThings是无参方法,Jackson无法识别为合法的Setter,自然不会生效。

推荐方案1:字段级自定义反序列化器(无全局影响)

这个方案只针对otherThings字段生效,不会改动其他业务逻辑的反序列化规则:

  1. 首先实现自定义反序列化器
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import java.io.IOException;
import java.util.TreeMap;

public class EmptyArrayAsEmptyTreeMapDeserializer extends StdDeserializer<TreeMap<String, MyOtherClass>> {

    public EmptyArrayAsEmptyTreeMapDeserializer() {
        super(TreeMap.class);
    }

    @Override
    public TreeMap<String, MyOtherClass> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        // 处理空数组场景
        if (parser.isExpectedStartArrayToken()) {
            // 跳过数组结束标记
            parser.nextToken();
            // 直接返回空TreeMap
            return new TreeMap<>();
        }
        // 正常对象场景走默认Map反序列化逻辑
        if (parser.isExpectedStartObjectToken()) {
            return context.readValue(parser, context.getTypeFactory().constructMapType(TreeMap.class, String.class, MyOtherClass.class));
        }
        // 其他非法类型抛出异常
        throw MismatchedInputException.from(parser, TreeMap.class, "只能从JSON对象或空数组反序列化TreeMap");
    }
}
  1. 调整MyClass中otherThings字段的注解,同时删除你原来写的无参setOtherThings方法:
@JsonSerialize(contentAs = MyOtherClass.class)
// 替换原来的@JsonDeserialize注解,绑定自定义反序列化器
@JsonDeserialize(using = EmptyArrayAsEmptyTreeMapDeserializer.class)
TreeMap<String, MyOtherClass> otherThings = new TreeMap<>();

方案2:Setter兼容处理(不需要新增类)

如果你不想额外新增反序列化器类,可以修改Setter方法自行处理类型兼容,还能避免覆盖已有数据:

// 移除字段上的@JsonDeserialize注解
TreeMap<String, MyOtherClass> otherThings = new TreeMap<>();

@JsonSetter("otherThings")
public void setOtherThings(JsonNode node) throws IOException {
    // 空数组场景直接保留已初始化的空TreeMap
    if (node.isArray() && node.isEmpty()) {
        return;
    }
    // 正常对象场景才做转换
    if (node.isObject()) {
        ObjectMapper mapper = new ObjectMapper();
        TreeMap<String, MyOtherClass> parsedValue = mapper.convertValue(node, new TypeReference<TreeMap<String, MyOtherClass>>() {});
        // 仅当解析结果非空时覆盖,避免清空已有数据
        if (parsedValue != null && !parsedValue.isEmpty()) {
            this.otherThings = parsedValue;
        }
    }
}

方案3:全局配置(适合多字段需要相同规则的场景)

如果你项目中多处存在需要将空数组转为空Map的场景,可以统一配置全局ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
// 先开启空数组转null配置
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT);
// 注册反序列化修改器,所有Map类型字段为null时自动初始化为空TreeMap
mapper.registerModule(new SimpleModule()
    .setDeserializerModifier(new BeanDeserializerModifier() {
        @Override
        public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
            if (TreeMap.class.isAssignableFrom(beanDesc.getType().getRawClass())) {
                return new JsonDeserializer<>() {
                    @Override
                    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                        Object result = deserializer.deserialize(p, ctxt);
                        return result == null ? new TreeMap<>() : result;
                    }
                };
            }
            return deserializer;
        }
    }));

注意:该方案会影响所有TreeMap类型字段的反序列化规则,如果你有其他TreeMap字段需要不同的初始化逻辑不要使用该方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 15:18:00