【问题标题】:JAXB serialize JsonElement field in POJOJAXB 序列化 POJO 中的 JsonElement 字段
【发布时间】:2017-05-29 09:18:16
【问题描述】:

我有一个 POJO 类,例如:

class Cat {
  public Cat() {}
  private String name;
  private JsonElement arbitraryProperties;
}

我正在使用 Jackson (JAXB),cat 是我要导入和导出的资源。

GET /cats/{id}
POST /cats

导出工作正常。导入不起作用,因为 JsonElement 是抽象的。所以我在arbitraryProperties field 中添加了@JsonDeserialize(using = MyJsonElementDeserialize.class) 注释。

MyJsonElementDeserialize 类看起来像:

public class JsonElementDeserialize extends JsonDeserializer<JsonElement> {

public JsonElementDeserialize() {
}

@Override
public JsonElement deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
    return new JsonObject(); // here I need to create my object later
}

}

当我现在使用有效负载调用 POST /cats 时:

{
  "name": "Mia",
  "arbitraryProperties": {
        "a": 3,
        "b": [],
        "c": {
            "d": "race"
        }
   }
 }

Jacksons 返回错误码 400:

无法识别的字段“a”(Cat 类),未标记为可忽略(1 个已知属性:“name”])。

我的错误在哪里?如何在我的 POJO 中有一个 JsonElement 自动序列化和反序列化?

【问题讨论】:

  • JsonElement 是什么?它是 GSON 的一部分吗?那为什么不使用呢?
  • 是的,JsonElement 是来自 GSON 的抽象类。 google.github.io/gson/apidocs/com/google/gson/JsonElement.html
  • 一个小建议:标题说“序列化”,但问题是关于“反序列化”。更改标题是有意义的,这样更容易找到相关问题。

标签: java json serialization jaxb jackson


【解决方案1】:

这是一个简单的解决方案,使用 Cat 中的 setter 方法将 Jackson 解析的内容(例如 Map&lt;String, Object&gt;)转换为 GSON JsonElement 类型:

void setArbitraryProperties(Map<String, Object> properties) {
    arbitraryProperties = new Gson().toJsonTree(properties).getAsJsonObject();
}

如果您不能在此处使用 setter,您可以在自定义反序列化器中执行类似的操作。我发现使用 Jackson 进行转换时 setter/getter 更简单。

请注意,Gson 实例用于将Map 转换为JsonElement(实际上是JsonObject)。 toJsonTree 的文档。

由于您在 GSON 中定义了一个类型的字段,因此您将 GSON 作为依赖项,并且不可避免地需要 GSON 来创建此字段,您可以考虑 Sharon 的建议并跳过 Jackson 并使用 GSON 进行反序列化。

【讨论】:

  • 我认为这是处理无法识别的字段的最佳方式。或者甚至更好地使用 Map 作为字段类型而不是 JsonElement。
【解决方案2】:

这里的问题是反序列化器必须消耗它们覆盖的所有内容:也就是说,如果您的反序列化器没有“读取”将绑定的 JSON 内容(此处为 a 的内容),它们将留待进一步处理。

解决方案应该很简单,只需调用

jsonParser.skipChildren();

deserialize 方法中,它会跳过当前输入令牌,以及它的所有内容(如果是它的 JSON 对象或数组)。

或者,如果你想使用内容,你可以使用

jsonParser.readValueAsTree();

还有其他一些方便的方法。

【讨论】:

    【解决方案3】:

    如果可以,我会将 JsonElement 更改为 JsonNode,并使用 Jackson 的“树模型”。

    【讨论】:

      【解决方案4】:

      如果您使用 Spring mvc,请尝试在控制器方法中使用“produces=MediaType.APPLICATION_JSON_VALUE”和@ResponseBody。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-08
        • 2020-05-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多