首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >具有“默认”对象类型的嵌套对象的动态反序列化

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

Stack Overflow用户
提问于 2021-07-08 08:29:15
回答 1查看 162关注 0票数 0

我想使用Jackson将对象动态反序列化为适当的java类,但是我很难正确地配置Jackson。

我有以下简化模型(为了简洁起见省略了getter/setters):

代码语言:javascript
复制
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;
}

在现实中,有不同类型的“特殊对象”,我希望能够在未来的需要时增加更多。

jsons看起来是这样的(我从外部来源获得它们,我不能更改发送它们的格式):

代码语言:javascript
复制
{
  "objType": "someType1",
  "commonProp": "example1..."
}
代码语言:javascript
复制
{
  "objType": "SPECIAL",
  "commonProp": "example2...",
  "specialProp": "more example"
}
代码语言:javascript
复制
{
  "objType": "someOtherType",
  "commonProp": "example3...",
  "nestedObject": {
    "objType": "SPECIAL",
    "commonProp": "example2...",
    "specialProp": "more example"
  }
}

我目前正像这样解析它们:

代码语言:javascript
复制
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);

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

我想要做的是告诉杰克逊:“无论嵌套级别,如果objType=SPECIAL,使用SpecialObject,否则使用GeneralObject”。我查看了多态反序列化并尝试使用@JsonSubTypes,但未能正确设置此逻辑。如何确保将特殊对象反序列化为适当的类,即使它们是嵌套的?

EN

回答 1

Stack Overflow用户

发布于 2021-07-08 11:25:24

我首先从这个要旨获得灵感,并试图用自定义TypeIdResolver来解决这个问题。不幸的是,这存在不正确地反序列化objType的问题(请参阅这个答案的第一个版本)。

然后,我从这个答案获得灵感,转而使用自定义的Deserializer

代码语言:javascript
复制
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的内容,并发出应该用于反序列化的适当(子)-class。反序列化器需要在GeneralObject上注册,例如使用以下注释:

代码语言:javascript
复制
@JsonDeserialize(using = CustomDeserializer.class)
class GeneralObject {
    ...
}

为了阻止无限递归循环的发生,必须对所有子类进行注释,以避免使用此自定义反序列化器,并且我们需要引入一个助手类来停止GeneralObject的递归。

代码语言:javascript
复制
@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
}

反序列化也适用于嵌套对象:

代码语言:javascript
复制
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);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68298083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档