用JAXB解组通用列表
问题内容:
我有一个返回此XML的服务:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<project>
<id>id1</id>
<owner>owner1</owner>
</project>
<project>
<id>id2</id>
<owner>owner2</owner>
</project>
</result>
要么
<?xml version="1.0" encoding="UTF-8"?>
<response>
<status>success</status>
<result>
<user>
<id>id1</id>
<name>name1</name>
</user>
<user>
<id>id2</id>
<name>name2</name>
</user>
</result>
我想使用以下类解组检索到的XML:
结果 :
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlElementWrapper(name = "result")
@XmlElement
protected List<T> result;
}
项目名称 :
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Project {
@XmlElement
public String id;
@XmlElement
public String owner;
}
用户名 :
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
@XmlElement
public String id;
@XmlElement
public String name;
}
首先不起作用的解决方案
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
我得到一个空名单。
第二不起作用的解决方案
受本文启发,http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-
jaxb.html
我修改了Response类:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlAnyElement(lax=true)
protected List<T> result;
}
然后使用以下代码对其进行测试:
Response<Project> responseProject = unmarshal(unmarshaller, Project.class, "responseProject.xml");
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
private static <T> Response<T> unmarshal(Unmarshaller unmarshaller, Class<T> clazz, String xmlLocation) throws JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
@SuppressWarnings("unchecked")
Response<T> wrapper = (Response<T>) unmarshaller.unmarshal(xml, Response.class).getValue();
return wrapper;
}
我在阅读响应列表时得到了这个异常:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
注意 :我无法修改原始XML。除项目和用户外,还有更多类型。
问题答案:
感谢Blaise Doughan和他的文章,我找到了解决方案。
首先,我们需要本文提供的Wrapper类:
@XmlRootElement
public class Wrapper<T> {
private List<T> items;
public Wrapper() {
items = new ArrayList<T>();
}
public Wrapper(List<T> items) {
this.items = items;
}
@XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
}
然后,我修改了Response类以便使用它:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlElement
protected Wrapper<T> result;
...
public Response(String status, List<T> result) {
this.status = status;
this.result = new Wrapper<>(result);
}
...
public List<T> getResult() {
return result.getItems();
}
...
}
最后是解组代码:
JAXBContext context = JAXBContext.newInstance(Response.class, Project.class, User.class, Wrapper.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
StreamSource source = new StreamSource(new File("responseProject.xml"));
Response<Project> responseProject = (Response<Project>)unmarshaller.unmarshal(source);
System.out.println(responseProject.getStatus());
for (Project project:responseProject.getResult()) System.out.println(project);
source = new StreamSource(new File("responseUser.xml"));
Response<User> responseUser = (Response<User>)unmarshaller.unmarshal(source);
System.out.println(responseUser.getStatus());
for (User user:responseUser.getResult()) System.out.println(user);
我已经将Wrapper类添加到上下文类列表中。
另外,您可以将此注释添加到Response类:
@XmlSeeAlso({Project.class, User.class})