8

この 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);

空のリストを取得します。

2番目の機能しないソリューション

この記事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 を変更することはできません。Project と User 以外にも種類があります。

4

2 に答える 2

14

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})
于 2013-11-09T20:18:36.497 に答える
1

応答クラスで @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&amp;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&amp;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>michzio@hotmail.com</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>alicja@krainaczarow.com</email>
            <login>alicja</login>
            <password>zAczka!00</password>
            <registrationDate>2015-09-03T17:30:03+02:00</registrationDate>
            <userId>2</userId>
        </user-account>
    </collection>
</resources>
于 2015-09-03T15:33:03.440 に答える