使用 JAXB 解组通用列表 [英] Unmarshalling generic list with JAXB

查看:55
本文介绍了使用 JAXB 解组通用列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个返回此 XML 的服务:

I've a service that returns this 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:

I want to unmarshall the retrieved XML using these classes:

结果:

@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 我修改了响应类:

Inspired by this article http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html I've modified the Response class:

@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

注意:我无法修改原始 XML.除了 Project 和 User 之外,还有更多类型.

Note: I can't modify the original XML. There are more types other than Project and User.

推荐答案

感谢 Blaise Doughan 和 他的文章 我找到了解决方案.

Thanks to Blaise Doughan and his article I've found the solution.

首先我们需要文章中提供的 Wrapper 类:

First we need the Wrapper class provided in the article:

@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 类以使用它:

Then I've modified the Response class in order to use it:

@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 类添加到上下文类列表中.

I've added the Wrapper class to the context class list.

或者,您可以将此注释添加到 Response 类:

Alternatively you can add this annotation to the Response class:

@XmlSeeAlso({Project.class, User.class})

这篇关于使用 JAXB 解组通用列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆