使用Jackson反序列化没有具体JavaType定义的自定义类型

qyyhg6bp  于 2022-11-23  发布在  Java
关注(0)|答案(1)|浏览(135)

我问自己是否(以及如何)可以使用Jackson转换特定的预定义类型。
给出如下结构示例:

{
  "dataValues": {"x": <anything>[, ...]}
}

基本上,这是一个Map,可以有 * 任何 *

  • 简单类型值(如String、int ...)
  • 另一张类似于"任何东西"Map
    • 任何内容 * 列表
  • 自定义类型(!问题来了)

正如你已经看到的,有一些选项和运行时未知的级联/ Package 。我唯一确定的是Map<String, Object> dataValues
受类型信息(第一种解决方案)的启发,我的大致想法是将自定义类型定义为:

{"type": "MyCustomType", "a":"Value1", "b":"Value2"}

我已经尝试过使用@JsonTypeInfo(和子类型,也就是activateDefaultTypeMapping...)来实现这一点,但是它们似乎只能与对象模型中的类型定义结合使用。
接下来,在介绍可能的解决方案时,我接受了事实,并为Object创建了一个反序列化器,因为我非常确定这是唯一的类型;)我缺少的是一个选项,可以将解析"非我的类型"的操作推迟到Map器。否则我就不得不为简单类型、列表、Map等编写Jackson的Map......同样糟糕。是的,我可以在其中创建另一个Map器,但它不知道"原始"Map器的配置。
唯一的方法,我得到这个工作不知何故是定义目标Map如下:

public class DataValues {
  @JsonCreator
  public DataValues(Map<String, Object> targetMap) {
    this.targetMap = targetMap.entrySet().stream().collect(Collectors.toMap(
            Map.Entry::getKey,
            map -> {
                Object newValue = map.getValue();
                newValue = optionalConversion(newValue);
                return newValue;
            }));
  }
}

然后决定是否要转换提供的map,或者它是否是一个包含普通值的嵌套map(或者是一个列表,或者是另一个map)。
我现在的心情是,也许我只是在JsonTypeInfo上遗漏了一点,或者我还没有找到一种方法来委托基于Object的反序列化器中的Map。或者(对我来说)未知的第三种选择是如此简单,以至于我从来没有想过。

wgmfuz8q

wgmfuz8q1#

我的解决方案现在是相当直接和简单的,因为它(可能)可以。
我想我缺少的是jsonParser.getCodec()来委托“已知未知”类型。在我的例子中,反序列化器的另一个好处是,我可以预先过滤Jackson可Map类型,只允许我想支持的简单类型。

private static class ParameterDeserializer extends JsonObjectDeserializer<Object> {

    @Override
    protected Object deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec, JsonNode tree) throws IOException {

        if (tree.isValueNode()) {
            if (tree.isTextual()) {
                return tree.asText();
            }
            if (tree.isFloatingPointNumber()) {
                return tree.asDouble();
            }
            if (tree.isBoolean()) {
                return tree.asBoolean();
            }
            if (tree.isInt()) {
                return tree.asInt();
            }
            if (tree.isNumber()) {
                return tree.asLong();
            }
        }
        if (tree.isContainerNode()) {
            if (tree.getNodeType().equals(JsonNodeType.ARRAY)) {
                return jsonParser.getCodec().treeToValue(tree, List.class);
            }
            if (tree.getNodeType().equals(JsonNodeType.OBJECT)) {
                JsonNode customType = tree.get("type");
                if (customType != null) {
                    // do custom conversion
                }

                return jsonParser.getCodec().treeToValue(tree, Map.class);
            }
        }
        throw new IllegalArgumentException("Cannot parse %s as a valid parameter type".formatted(tree));

    }
}

相关问题