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

如何通过Jackson ObjectMapper将JSON直接反序列化为Map<String, Set<Key>>

问题描述

现有如下结构的JSON对象:

{
  "key1": {
    "code1": "name1",
    "code2": "name2",
    ...
  },
  "key2": {
    "code1": "name1",
    "code2": "name2",
    ...
  },
  ...
}

需要将其直接反序列化为Map<String, Set<Key>>类型,而非Jackson默认支持的Map<String, Map<String, String>>。Key类定义如下:

public class Key{
  private String code;
  private String Name;
}

自定义了反序列化器但运行时报错:

public static class KeyListDeserializer extends JsonDeserializer<Set<Key>> {

    @Override
    public Set<Key> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        Set<Key> keyList = new HashSet<>();
        JsonNode rootNode = jp.getCodec().readTree(jp);

        Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> field = fields.next();
            String code = field.getKey();
            String name = field.getValue().asText();

            Key key = new Key();
            key.setCode(code);
            key.setName(name);

            keyList.add(key);
        }

        return keyList;
    }
}

报错信息:

Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.HashSet<um.Test1$Key>` from Object value (token `JsonToken.START_OBJECT`)
解决方案

报错核心原因:Jackson默认认为Set类型对应JSON数组,但你的JSON中每个分组(如key1)的值是JSON对象而非数组,因此需要明确告知Jackson为Set<Key>类型绑定自定义反序列化器,并正确配置ObjectMapper。

步骤1:修正Key类(必要)

原Key类中Name首字母大写,不符合Java驼峰命名规范,Jackson默认会按小写首字母匹配属性,同时必须添加getter/setter方法,否则Jackson无法完成属性赋值:

public class Key {
    private String code;
    private String name;

    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

步骤2:注册自定义反序列化器并完成反序列化

通过SimpleModule将自定义反序列化器绑定到Set<Key>类型,借助TypeReference解决Java泛型擦除问题,直接反序列化为目标类型:

public class Main {
    public static void main(String[] args) throws IOException {
        String json = "{\"key1\":{\"code1\":\"name1\",\"code2\":\"name2\"},\"key2\":{\"code3\":\"name3\"}}";
        
        // 创建模块并注册反序列化器
        SimpleModule module = new SimpleModule();
        module.addDeserializer(new TypeReference<Set<Key>>() {}, new KeyListDeserializer());
        
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(module);
        
        // 直接反序列化为Map<String, Set<Key>>
        Map<String, Set<Key>> result = objectMapper.readValue(
            json, 
            new TypeReference<Map<String, Set<Key>>>() {}
        );
        
        // 验证结果
        for (Map.Entry<String, Set<Key>> entry : result.entrySet()) {
            System.out.println("分组:" + entry.getKey());
            for (Key key : entry.getValue()) {
                System.out.printf("  Code: %s, Name: %s%n", key.getCode(), key.getName());
            }
        }
    }
    
    // 自定义反序列化器(保留原有逻辑即可)
    public static class KeyListDeserializer extends JsonDeserializer<Set<Key>> {
        @Override
        public Set<Key> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
            Set<Key> keySet = new HashSet<>();
            JsonNode rootNode = jp.getCodec().readTree(jp);
            
            Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> field = fields.next();
                Key key = new Key();
                key.setCode(field.getKey());
                key.setName(field.getValue().asText());
                keySet.add(key);
            }
            return keySet;
        }
    }
}

关键说明

  • 使用TypeReference指定泛型类型:由于Java泛型擦除,直接传入Map.class无法让Jackson识别内层的Set<Key>泛型参数,必须用TypeReference包装。
  • 模块注册的优势:这种方式属于全局配置,后续所有需要反序列化为Set<Key>的场景都会自动使用该反序列化器,无需重复注解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:10:18