【问题标题】:Custom Jackson deserializer not able to determine target class自定义杰克逊反序列化器无法确定目标类
【发布时间】:2011-10-05 10:56:20
【问题描述】:

我目前有一个 Join 对象,我正在尝试为其编写自定义反序列化程序。我们将数据库键和对象的 Java 类名存储在 JSON 中,看起来像这样:

{
    "@class": "com.mysite.data.ExpertFor",
    "id": "expert-for-1",
    "leftId": "user-profile-1",
    "leftType": "com.mysite.data.UserProfile",
    "rightId": "hotel-1",
    "rightType": "com.mysite.data.Hotel"
}

我们这样做是为了不必将实际对象存储在数据库中;相反,我们在反序列化它时检索它。问题是我的自定义序列化程序在 JSON 流中看不到 @class 元素 - 因此,在读取所有数据后它无法正确实例化所需的对象。这是我的反序列化器:

public Join deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
    Map<String, Object> values = new HashMap<String, Object>();

    // Loop through the JSON document and pull out all
    // the values and put them into the map
    JsonToken token = jp.nextToken();
    while (token != JsonToken.END_OBJECT) {
        logger.info("Non-data field: [" + token + "], name is [" + jp.getCurrentName() + "], text is [" + jp.getText() + "]");
        if (token == JsonToken.VALUE_STRING) {
            values.put(jp.getCurrentName(), jp.getText());
        }
        token = jp.nextToken();
    }         
    // remainder of code omitted for brevity
}    

现在,写入日志的 Log4J 行显示了我期望的 JSON 的所有适当元素,除了 @class 元素

Data field: [VALUE_STRING], name is [id], text is [expert-for-1]
Data field: [VALUE_STRING], name is [leftId], text is [user-profile-1]
Data field: [VALUE_STRING], name is [rightId], text is [hotel-1]
Data field: [VALUE_STRING], name is [leftType], text is [com.mysite.data.UserProfile]
Data field: [VALUE_STRING], name is [rightType], text is [com.mysite.data.Hotel]

我已经尝试将@JsonTypeInfo 注释添加到我的类中,例如

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") 

但该元素似乎被代码“吞噬”了,我不知道如何处理它。我需要这个,因为Join 的任何后代都需要反序列化。以下是有关此类所在层次结构的一些附加信息:

添加@TypeInfo 注释只是为了尝试看看发生了什么。无论是否存在,我都会得到相同的行为。真正奇怪的是,我们在其他需要自定义反序列化的类中使用了相同的基本功能,而那些看到 @class 就好了。这是它的层次结构:

@JsonAutoDetect(value = JsonMethod.NONE)
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
public abstract class TaggedObject implements Serializable {
...
}

然后我们有 DataObject

public abstract class DataObject extends TaggedObject {
...
}

然后我们就有了 Join 类:

@JsonSerialize(using = Join.Serializer.class)
@JsonDeserialize(using = Join.Deserializer.class)
public abstract class Join<L, R> extends DataObject {
...
}

我认为@JsonTypeInfo 将继承自 TaggedObject,但在这里看不到,而同一层次结构中的其他类可以看到它。

任何人对如何获取该对象的类以便创建适当的对象有任何想法?我在这里错过了什么?

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    您不应该尝试手动处理 @class 并使用 @JsonTypeInfo 将其声明为由 Jackson 处理 - 让 Jackson 完全处理它(它可以并且将会这样做),或者删除 anntoation 并手动处理。

    【讨论】:

      【解决方案2】:

      使用杰克逊树模型,以下代码打印缺少的@class

      ObjectMapper mapper = new ObjectMapper();
      JsonNode root = mapper.readTree(jsonString);
      Iterator<String> iterator = root.fieldNames();
      while (iterator.hasNext()) {
          String fieldName = iterator.next();
          String fieldValue = root.get(fieldName).asText();
          System.out.println("name is [" + fieldName + "], text is [" + fieldValue + "]");
      }
      

      输出:

      name is [@class], text is [com.mysite.data.ExpertFor]
      name is [id], text is [expert-for-1]
      name is [leftId], text is [user-profile-1]
      name is [leftType], text is [com.mysite.data.UserProfile]
      name is [rightId], text is [hotel-1]
      name is [rightType], text is [com.mysite.data.Hotel]
      

      【讨论】:

      • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-31
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      • 2018-04-02
      • 2013-08-11
      • 2015-03-12
      相关资源
      最近更新 更多