使用Jackson反序列化具有整数键的映射

9

我需要将一个简单的整数到字符串的映射序列化为JSON,然后再读取它。序列化很简单,但由于JSON键必须是字符串,因此生成的JSON看起来像:

{
  "123" : "hello",
  "456" : "bye",
}

当我使用以下代码阅读它时:

new ObjectMapper().readValue(json, Map.class)

我得到了一个 Map<String, String>,但我需要的是 Map<Integer, String>

我尝试添加键解析器,如下所示:

    Map<Integer, String> map1 = new HashMap<>();
    map1.put(1, "foo");
    map1.put(2, "bar");


    ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addKeyDeserializer(Integer.class, new KeyDeserializer() {
        @Override
        public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            System.out.println("deserialize " + key);
            return Integer.parseInt(key);
        }
    });

    mapper.registerModule(module);
    String json = mapper.writeValueAsString(map1);


    Map map2 = mapper.readValue(json, Map.class);
    System.out.println(map2);
    System.out.println(map2.keySet().iterator().next().getClass());

很遗憾我的key deserializer从未被调用,而map2实际上是Map<String, String>,因此我的示例打印出:
{1=foo, 2=bar}
class java.lang.String

我做错了什么,如何解决这个问题?

我遇到了同样的问题。很惊讶你没有更多的赞。 - Anton Belev
1个回答

15

使用

Map<Integer, String> map2 = 
        mapper.readValue(json, new TypeReference<Map<Integer, String>>(){});
或者
    Map<Integer, String> map2 = 
        mapper.readValue(json, TypeFactory.defaultInstance()
                         .constructMapType(HashMap.class, Integer.class, String.class));
你的程序将输出下面的文本:
deserialize 1
deserialize 2
{1=foo, 2=bar}
class java.lang.Integer

太棒了,非常感谢。这肯定是对我最好的解决方案。不过,为什么我的解决方案不起作用还是很有趣的。 - AlexR
4
Jackson不知道你的Map中键和值的类型,需要告诉它。如果你要将其反序列化为POJO,且该POJO具有Map<Integer, String>,则Jackson似乎知道如何处理。但是,当直接解析Map时,以上内容似乎是告诉Jackson如何处理的方式。 - Wand Maker
我明白了,现在清楚了。非常感谢您的解释。 - AlexR
1
即使我在mapper.readValue(json, Map.class)的左侧使用了map1,为什么它不会报错? map1的键是Integer,但是当我使用getClass()时,它被打印为String。 在反序列化过程中发生了什么? - Thiyagu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接