杰克逊自定义列表实例类型

时间:2017-04-21 00:16:08

标签: java json jackson json-deserialization

我需要将标准Json数组映射到自定义List类型(实际上不是java.util.List,而是javaslang.collection.List)。除了复杂性之外,我们还没有静态bean,我们可以将列表类型定义为javaslang类型,但是我们需要映射到通用Map,但列表实例应该是javaslang.collection.List类型。

我尝试创建新的自定义反序列化器,但由于我们正在尝试使用通用Map,因此根本不会触及该自定义反序列化器。

例如,这是我们希望通过的测试用例。

@Test
@DisplayName("list instance is javaslang list")
void listAsJsList() throws Exception {
    Map<String, Object> object = objectMapper.readValue(
            "{\"records\": [{\"id\": \"123\"}, {\"id\": \"124\"} ] }", HashMap.class);
    assertThat(object.get("records")).isInstanceOf(javaslang.collection.List.class);
}

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

为Map编写反序列化器可以获得所需的结果。像这样:

class MapDeserializer extends JsonDeserializer<Map<String, Object>> {

    @Override
    public Map<String, Object> deserialize(JsonParser paramJsonParser, DeserializationContext paramDeserializationContext)
            throws IOException, JsonProcessingException {
        JsonNode node = paramJsonParser.getCodec().readTree(paramJsonParser);
        return parseObject(node);
     }

    private Map<String, Object> parseObject(JsonNode node) {
        Map<String, Object> object = new HashMap<String, Object>();
        Iterator<Map.Entry<String, JsonNode>> itr = node.fields();
        while (itr.hasNext()) {
            Map.Entry<String, JsonNode> entry = itr.next();
            if (entry.getValue().isArray())
                object.put(entry.getKey(), parseArray(entry.getValue()));
            else if (entry.getValue().isObject())
                object.put(entry.getKey(), parseObject(entry.getValue()));
            else
                object.put(entry.getKey(), entry.getValue().asText());
        }
        return object;
    }

    private List<Object> parseArray(JsonNode node) {
        List<Object> list = List.of();
        Iterator<JsonNode> itr = node.elements();
        while (itr.hasNext()) {
            JsonNode currentNode = itr.next();
            if (currentNode.isObject())
                list = list.prepend(parseObject(currentNode));
            else if (currentNode.isArray())
                list = list.prepend(parseArray(currentNode));
            else
                list = list.prepend(currentNode.asText());
        }
        return list;
     }
}

注意:

  • 上面的代码也会将内部对象解析为类型为hashmaps的实例,可以根据需要更改实现。
  • 可以添加更多案例来处理字符串,整数等作为各自类型的实例,并且可以在需要时进行异常处理。

以上反序列化程序的示例用法:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Map.class, new MapDeserializer());
mapper.registerModule(module);
Map<String, Object> result = mapper.readValue("{\"records\": [{\"id\": \"123\"}, {\"id\": \"124\"} ] }", Map.class);
if (result.get("records") instanceof javaslang.collection.List) {
    System.out.println("records are of type javaslang list");
}
// Prints: records are of type javaslang list