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

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

问题描述

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

 <?xml version =1.0encoding =UTF -8\" >?; 
<回应>
<状态>成功< /状态>
<结果>
< project>
< id> id1< / id>
< owner> owner1< / owner>
< / project>
< project>
< id> id2< / id>
< owner> owner2< / owner>
< / project>
< / result>



 <?xml version =1.0encoding =UTF-8?> 
<回应>
<状态>成功< /状态>
<结果>
< 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
保护字符串状态;

@XmlElementWrapper(name =result)
@XmlElement
保护List< T>结果;
}

项目

  @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));
响应< 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));
响应<用户> 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
保护字符串状态;

@XmlAnyElement(lax = true)
受保护的列表< T>结果;
}

然后用下面的代码测试它:

 回应< 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>应答LT; T> unmarshal(Unmarshaller unmarshaller,Class< T> clazz,String xmlLocation)引发JAXBException {
StreamSource xml = new StreamSource(xmlLocation);
@SuppressWarnings(unchecked)
响应< T> wrapper =(Response< T>)unmarshaller.unmarshal(xml,Response.class).getValue();
返回包装;
}

我得到这个异常读取响应列表:

 线程main中的异常java.lang.ClassCastException:com.sun.org.apache.xerces.internal.dom.ElementNSImpl无法转换为org .test.Project 

注意:我无法修改原始XML 。除了Project和User以外,还有更多的类型。 解决方案

感谢Blaise Doughan和他的文章,我找到了解决方案。 / p>

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

  @ XmlRootElement 
public class Wrapper< T> {

私人列表< T>项目;

public Wrapper(){
items = new ArrayList< T>();
}

public Wrapper(List< T> items){
this.items = items;
}

@XmlAnyElement(lax = true)
public List< T> getItems(){
返回项目;


然后我修改了Response类以便使用它:

  @XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD)
public class Response< T> {

@XmlElement
保护字符串状态;

@XmlElement
保护包装< T>结果;

...

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。类); 
Unmarshaller unmarshaller = context.createUnmarshaller();

StreamSource source = new StreamSource(new File(responseProject.xml));
响应< 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));
响应<用户> 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})


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>

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:

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.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

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

解决方案

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

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;
  }
}

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();
  }

  ...
}

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.

Alternatively you can add this annotation to the Response class:

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

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

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