java - 配置XStream动态映射到不同的对象

标签 java json jackson xstream oxm

我正在使用 RESTful 第三方 API,它始终以以下格式发送 JSON:

{
    "response": {
        ...
    }
}

其中 ... 是需要映射回 Java POJO 的响应对象。例如,有时 JSON 将包含应映射回 Fruit POJO 的数据:

{
    "response": {
        "type": "orange",
        "shape": "round"
    }
}

...有时 JSON 会包含应映射回 Employee POJO 的数据:

{
    "response": {
        "name": "John Smith",
        "employee_ID": "12345",
        "isSupervisor": "true",
        "jobTitle": "Chief Burninator"
    }
}

因此,根据 RESTful API 调用,我们需要将这两个 JSON 结果映射回两者之一:

public class Fruit {
    private String type;
    private String shape;

    // Getters & setters for all properties
}

public class Employee {
    private String name;
    private Integer employeeId;
    private Boolean isSupervisor;
    private String jobTitle;

    // Getters & setters for all properties
}

不幸的是,我无法改变这个第 3 方 REST 服务始终发回 { "response": { ... } } JSON 结果的事实。但我仍然需要一种方法来配置映射器,以将此类响应动态映射回Fruit 或Employee。

首先,我尝试了Jackson取得了有限的成功,但它的可配置性并不像我想要的那样。所以现在我尝试使用 XStream及其用于将 JSON 映射回 POJO 的 JettisonMappedXmlDriver。这是我的原型(prototype)代码:

public static void main(String[] args) {
    XStream xs = new XStream(new JettisonMappedXmlDriver());

    xs.alias("response", Fruit.class);
    xs.alias("response", Employee.class);

    // When XStream sees "employee_ID" in the JSON, replace it with
    // "employeeID" to match the field on the POJO.
    xs.aliasField("employeeID", Employee.class, "employee_ID");

    // Hits 3rd party RESTful API and returns the "*fruit version*" of the JSON.
    String json = externalService.getFruit();

    Fruit fruit = (Fruit)xs.fromXML(json);
}

不幸的是,当我运行这个程序时,我遇到了异常,因为我有 xs.alias("response", ...)response 映射到 2 个不同的 Java 对象:

Caused by: com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$UnknownFieldException: No such field me.myorg.myapp.domain.Employee.type
---- Debugging information ----
field               : type
class               : me.myorg.myapp.domain.Employee
required-type       : me.myorg.myapp.domain.Employee
converter-type      : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
path                : /response/type
line number         : -1
version             : null
-------------------------------

所以我问:我能做些什么来避免 API 总是发回相同的“包装器”响应 JSON 对象这一事实? 我唯一能做的就是首先想到的是像这样进行字符串替换:

String json = externalService.getFruit();
json = json.replaceAll("response", "fruit");
...

但这似乎是一个丑陋的黑客行为。 XStream(或其他映射框架)是否提供了任何可以帮助我解决这种特殊情况的东西?提前致谢。

最佳答案

jackson 有两种方法:

  • 手动测试所需的键是否存在(JsonNode 具有必要的方法);
  • 使用 JSON 架构; Java中有一个API:json-schema-validator (是的,那是我的),它使用 Jackson。

编写与您的第一个对象类型匹配的模式:

{
    "type": "object",
    "properties": {
        "type": {
            "type": "string",
            "required": true
        },
        "shape": {
            "type": "string",
            "required": true
        }
    },
    "additionalProperties": false
}

将其作为模式加载,根据它验证您的输入:如果它验证,您知道您需要针对您的水果类进行反序列化。否则,为第二个项目类型创建架构,将其作为安全措施进行验证,然后使用其他类进行反序列化。

code examples for the API ,也是(版本 1.4.x)

关于java - 配置XStream动态映射到不同的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14123339/

相关文章:

java - 调用运行时编译的类的自定义方法

java - Gson 与 Hibernate - 尝试加载惰性属性时出错

php - jQuery ajax() 返回 json 对象但未正确发出警报

Hibernate 级联 ="all-delete-orphan",不删除孤儿

java - 为什么 Jackson 多态序列化在列表中不起作用?

java - 实现堆排序的正确方法是什么?

Java 8 : Observable List - Invalidation Listener nor Change Listener is called in case of property change

java - 如何创建像新的 YouTube 应用程序一样的多任务视频 Activity ?

iphone - 在 iphone 中使用 Brautaset Json 框架时出错

java - 使用 @JsonAnyGetter/@JsonAnySetter 序列化 JSON 并更改属性名称 (Jackson)