Java 使用 JAXB 解组通用列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19878229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unmarshalling generic list with JAXB
提问by Fedy2
I've a service that returns this XML:
我有一个返回此 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>
or
或者
<?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>
I want to unmarshall the retrieved XML using these classes:
我想使用这些类解组检索到的 XML:
Result:
结果:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Response<T> {
@XmlElement
protected String status;
@XmlElementWrapper(name = "result")
@XmlElement
protected List<T> result;
}
Project:
项目:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Project {
@XmlElement
public String id;
@XmlElement
public String owner;
}
User:
用户:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class User {
@XmlElement
public String id;
@XmlElement
public String name;
}
First not working solution
首先不工作的解决方案
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);
I get an empty list.
我得到一个空列表。
Second not working solution
第二个不工作的解决方案
Inspired by this article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.htmlI've modified the Response class:
受这篇文章的启发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;
}
And then tested it with this code:
然后使用以下代码对其进行测试:
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;
}
And I get this exception reading the response list:
我在阅读响应列表时遇到了这个异常:
Exception in thread "main" java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to org.test.Project
Note: I can't modify the original XML. There are more types other than Project and User.
注意:我无法修改原始 XML。除了 Project 和 User 之外,还有更多类型。
采纳答案by Fedy2
Thanks to Blaise Doughan and his articleI've found the solution.
感谢 Blaise Doughan 和他的文章,我找到了解决方案。
First we need the Wrapper class provided in the article:
首先我们需要文章中提供的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;
}
}
Then I've modified the Response class in order to use it:
然后我修改了 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();
}
...
}
Finally the unmarshalling code:
最后是解组代码:
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);
I've added the Wrapper class to the context class list.
我已将 Wrapper 类添加到上下文类列表中。
Alternatively you can add this annotation to the Response class:
或者,您可以将此注释添加到 Response 类:
@XmlSeeAlso({Project.class, User.class})
回答by Micha? Ziobro
Using @XmlSeeAlso({Project.class, User.class})on Responseclasses has the drawback of generating some garbage information on each entity in the list: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount"
在响应类上使用@XmlSeeAlso({Project.class, User.class})的缺点是会在列表中的每个实体上生成一些垃圾信息:xmlns:xsi="http://www.w3.org/2001/XMLSchema -instance" xsi:type="userAccount"
<resources>
<links>
<link>
<rel>self</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=0&limit=2</uri>
</link>
<link>
<rel>prev</rel>
<uri></uri>
</link>
<link>
<rel>next</rel>
<uri>http://localhost:8080/salonea-1.0/rest/user-accounts?offset=2&limit=2</uri>
</link>
</links>
<collection>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>638f502a0e409348ccc2e36c24907f0</activationCode>
<email>[email protected]</email>
<login>michzio</login>
<password>sAmPL3#e</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>1</userId>
</user-account>
<user-account
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="userAccount">
<accountType>user</accountType>
<activationCode>334bc79d142a291894bd71881e38a719</activationCode>
<email>[email protected]</email>
<login>alicja</login>
<password>zAczka!00</password>
<registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
<userId>2</userId>
</user-account>
</collection>
</resources>