灵活的 JAXB XML 解析泛型和特定类型或该类型的列表

Flexible JAXB XML parsing for generics and a particular type or a list of that type

我正在和一位同事的 API 一起工作。 API return 是一个 Response,其中包含对象列表或只有一个对象。对象可以是多种类型。 return 类型在 XML 中。我有兴趣通过 JAXB 解析此 XML 以获得我的 classes,理想情况下是以灵活和通用的方式。

以下两个 XML 回复是我所说内容的示例。

示例 1:包含 Job 对象的列表 Jobs 的响应。

<Response>
   <Status>OK</Status>
   <Jobs>
        <Job>
            <ID>J1</ID>
            <Name>job name</Name> 
        </Job>
        <Job>
            <ID>J2</ID>
            <Name>job name</Name> 
        </Job>
    </Jobs>
</Response>

示例 2:一个 Job.

的响应
<Response>
    <Status>OK</Status> 
    <Job>
        <ID>J123</ID> 
        <Name>job name</Name> 
    </Job>
</Response>

目前,我正在构建如下内容:

@XmlRootElement(name="Response")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response {
    @XmlElement(name = "Status")
    protected Status status;
    @XmlAnyElement(lax=true)
    protected Object items;
}

解组通过

   Response = (Response) unmarshaller.unmarshal(myXmlResponse);

但在解组 Sample 1 时,我的项目中收到了 null。此外,这种方法给我一种不好的感觉,因为我使用 Object 作为包罗万象,即期望 List<Job>Job 类型。我究竟做错了什么?有更好的解决方案吗?也许我的回复 class 可以有两个泛型,一个用于 item 列表,另一个用于单个 item?

将单数 <Job> 转换为具有一个元素的 job 列表的方法也很有趣,但我不确定如果不修改XML 响应。

你可以这样做:

@XmlRootElement(name = "Response")
public class Response {

    @XmlElement(name ="Status")
    private Status status;

    @XmlElements({
            @XmlElement(name = "Job", type = Job.class),
            @XmlElement(name = "Jobs", type = Jobs.class),
    })
    private List<?> jobs;
}

那么工作将是:

public class Job {

    @XmlElement(name = "ID")
    private String id;
    @XmlElement(name = "Name")
    private String name;
}

还有乔布斯:

public class Jobs {

    @XmlElement(name = "Job")
    private List<Job> jobs;
}

更新以回答评论:

这是我能想到的处理这些描述的有效负载的最干净的方法。挑战在于 <Jobs></Jobs> 只出现了几次。

有一种方法可以在没有嵌入列表的情况下做到这一点,但它比较混乱。我会在下面复制它,这样你就可以决定是否喜欢它,或者更好地获得另一个更清洁的解决方案。

@XmlRootElement(name = "Response")
public class Response {

    @XmlElement(name ="Status")
    private Status status;

    @XmlElement(name = "Job")
    private List<Job> jobs;

    @XmlElementWrapper(name = "Jobs")
    @XmlElement(name = "Job")
    private List<Job> jobsWrapped;

}