当前位置: 首页 > 知识库问答 >
问题:

具有“默认”对象类型的嵌套对象的动态反序列化

骆文彬
2023-03-14
class GeneralObject {
    public String objType;
    public String commonProp;
    public GeneralObject nestedObject;

    // map for additional properties, so that I can re-serialize the full object later
    public Map<String, JsonNode> additionalFields = new HashMap<>();
    @JsonAnyGetter
    public Map<String, JsonNode> getAdditionalFields() {
        return additionalFields;
    }
    @JsonAnySetter
    public void addAdditionalField(String fieldName, JsonNode value) {
        this.additionalFields.put(fieldName, value);
    }
}

class SpecialObject extends GeneralObject {
    public String specialProp;
}
{
  "objType": "someType1",
  "commonProp": "example1..."
}
{
  "objType": "SPECIAL",
  "commonProp": "example2...",
  "specialProp": "more example"
}
{
  "objType": "someOtherType",
  "commonProp": "example3...",
  "nestedObject": {
    "objType": "SPECIAL",
    "commonProp": "example2...",
    "specialProp": "more example"
  }
}
ObjectMapper mapper = new ObjectMapper();
String objString = "{\"objType\": \"SPECIAL\", \"commonProp\": \"...\", \"specialProp\": \"more example\"}";
GeneralObject genObj = mapper.readValue(objString, GeneralObject.class);
if (genObj.objType.equals("SPECIAL")) {
    genObj = mapper.readValue(objString, SpecialObject.class);
}
// Some business-logic: If SPECIAL, then this cast is required to work:
System.out.println(((SpecialObject) genObj).specialProp);

这适用于顶级对象,但不适用于嵌套对象。例如,如果嵌套对象是特殊对象,则仍将其反序列化为公共对象。

我想做的是告诉Jackson:“无论嵌套级别如何,如果ObjType=Special,使用SpecialObject,否则使用GeneralObject”。我研究了多态反序列化,并尝试使用@JSONSubtypes,但无法正确设置该逻辑。如何确保特殊对象被反序列化到适当的类中,即使它们是嵌套的?

共有1个答案

庄阿苏
2023-03-14

我首先尝试从这个要点中获得灵感,我想用自定义的TypeIDResolver来解决这个问题,但是这个问题不能正确地反序列化ObjType(请参阅本答案的第一版)。

然后切换到自定义的反序列化器:

class CustomDeserializer extends StdDeserializer<GeneralObject> {

    private static final String SPECIAL = "\"SPECIAL\"";

    protected CustomDeserializer() {
        super(GeneralObject.class);
    }

    @Override
    public GeneralObject deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
        TreeNode node = p.readValueAsTree();

        // Select appropriate class based on "resourceType"
        TreeNode objTypeNode = node.get("objType");
        if (null == objTypeNode) {
            throw new JsonParseException(p, "field \"objType\" is missing!");
        }
        if (!objTypeNode.isValueNode()) {
            throw new JsonParseException(p, "field \"objType\" must be a String.");
        }
        String objType = objTypeNode.toString();
        Class<? extends GeneralObject> clazz;
        if (objType.equals(SPECIAL)) {
            clazz = SpecialObject.class;
        } else {
            clazz = RecursionStopper.class;
        }
        return p.getCodec().treeToValue(node, clazz);
    }
}

它检查.objtype的内容,并发出应该用于反序列化的适当(子)类。需要在GeneralObject上注册反序列化器,例如使用以下注释:

@JsonDeserialize(using = CustomDeserializer.class)
class GeneralObject {
    ...
}
@JsonDeserialize(using = JsonDeserializer.None.class)
class SpecialObject extends GeneralObject {
    public String specialProp;
}

@JsonDeserialize(using = JsonDeserializer.None.class)
class RecursionStopper extends GeneralObject {
    // this class intentionally empty
}

ObjectMapper mapper = new ObjectMapper();
String objString = "{\n" +
        "  \"objType\": \"someObjType\",\n" +
        "  \"commonProp\": \"example3...\",\n" +
        "  \"nestedObject\": {\n" +
        "    \"objType\": \"SPECIAL\",\n" +
        "    \"commonProp\": \"example2...\",\n" +
        "    \"specialProp\": \"more example\"\n" +
        "  }\n" +
        "}";
GeneralObject genObj = mapper.readValue(objString, GeneralObject.class);
System.out.println(((SpecialObject) genObj.nestedObject).specialProp);
 类似资料:
  • 我正试图找到一种方法来使用jackson的多态反序列化功能,它将基于嵌套在标头/控件对象中的属性反序列化我的对象: JSON 1-类别1: JSON 2-类别2 父类(类似这样的注释) 子类 jackson中是否有现成的功能可以让我进行这种反序列化,或者我遗漏了什么?

  • 但它返回一个id为空且产品为空的对象。当然,我不需要为这个简单的操作编写自定义的吗?

  • 我对对象接口的jackson序列化有问题。 我有课 哪个实现 还有上课 哪个实现 上课 我要和Jackson连载Container得到结果 但事实上我得到了结果 尽管我在映射中指定了点的序列化类型(),但在嵌套对象“point”中具有属性“name”。接口点视图没有方法getName,但结果中存在点的字段“name”。 若我从类容器中的方法getMap中删除注释(),我将得到结果 现在点没有属性"

  • 问题内容: 我从看起来像这样的API获取JSON: 我尝试了几种方法来在c#对象中表示此JSON(太多内容无法在此处列出)。我已经尝试过使用列表和字典,这是我尝试表示它的最新示例: 这是我用来反序列化JSON的方法: 包含和。并且包含,但是是。因此,除了反序列化之外,什么都没有。 它应该很简单,但是由于某种原因我无法弄清楚正确的对象表示形式 问题答案: 要使用,即: 假设项目名称和随响应而变化,并

  • 我认为最好用一个例子来解释。 我有一个想要反序列化的JSON对象,它包含一个接口类型列表以及列表中的类型,但是我不确定如何让反序列化器确定列表中的具体类型: 要反序列化的类型 界面 儿童 我知道如果类型不是<code>List</code>,我可以将类型与<code>JsonSubTypes</code>一起使用,例如: 如果在父类型内,也是如此。但是当类型在类之外时,是否有一种方法可以帮助反序列

  • 问题内容: 我有一个名为的类,该类具有一个作为参数的构造函数: 具有以下属性: 并且是我的应用程序的其他类,并具有以下构造函数: ,并且是的子类。 我想用Gson 反序列化数组,所以我写道: 以定义为: 调试时,实例具有正确的“ MainActivity”作为上下文,而其成员变量的上下文为null。 Gson 使用正确的构造函数创建了对象,但使用默认的无参数构造函数创建了实例。我怎样才能解决这个问