如何使用JAXB从服务返回的'anyType'创建java对象?

时间:2012-01-31 13:23:58

标签: java serialization jaxb unmarshalling

Web服务将WSDL定义的对象返回为:

<s:complexType mixed="true"><s:sequence><s:any/></s:sequence></s:complexType>

当我打印出这个对象的课程信息时,它会显示为:

class com.sun.org.apache.xerces.internal.dom.ElementNSImpl

但我需要将此对象解组为以下类的对象:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "", propOrder = {
        "info",
        "availability",
        "rateDetails",
        "reservation",
        "cancellation",
        "error" }) 
@XmlRootElement(name = "ArnResponse") 
public class ArnResponse { }

我知道答案是正确的,因为我知道如何编组这个对象的XML:

Marshaller m = jc.createMarshaller();
m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
m.marshal(rootResponse, System.out);

打印出来:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:SubmitRequestDocResponse xmlns:ns2="http://tripauthority.com/hotel">
    <ns2:SubmitRequestDocResult>
        <!-- below is the object I'm trying to unmarshall -->
        <ArnResponse>
            <Info />
            <Availability>
                <!-- etc--> 
             </Availability>
        </ArnResponse>
    </ns2:SubmitRequestDocResult>
</ns2:SubmitRequestDocResponse>

如何将我看到的ElementNSImpl对象转换为我所知道的ArnResponse对象?

此外,我正在AppEngine上运行,其中文件访问受到限制。

感谢您的帮助

更新

我添加了@XmlAnyElement(lax=true)注释,如下所示:

  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlType(name = "", propOrder = {
      "content"
  })
  @XmlSeeAlso(ArnResponse.class)
  public static class SubmitRequestDocResult {

    @XmlMixed
    @XmlAnyElement(lax = true)
    protected List<Object> content;

但它没有任何区别。

这是否与内容为List

的事实有关

以下是我从服务器取回内容后尝试访问内容的代码:

List list = rootResponse.getSubmitRequestDocResult().getContent();

for (Object o : list) {
  ArnResponse response = (ArnResponse) o;
  System.out.println(response);
}

哪个有输出:

  

2012年1月31日上午10:04:14   com.districthp.core.server.ws.alliance.AllianceApi getRates严重:   com.sun.org.apache.xerces.internal.dom.ElementNSImpl无法强制转换为   com.districthp.core.server.ws.alliance.response.ArnResponse

答案:

axtavt的答案就行了。这很有效:

Object content = ((List)result.getContent()).get(0);
JAXBContext context = JAXBContext.newInstance(ArnResponse.class);
Unmarshaller um = context.createUnmarshaller();
ArnResponse response = (ArnResponse)um.unmarshal((Node)content);
System.out.println("response: " + response);

3 个答案:

答案 0 :(得分:18)

您可以将该对象传递给Unmarshaller.unmarshal(Node),它应该可以解组它。

答案 1 :(得分:4)

您可以使用@XmlAnyElement(lax=true)。这会将具有已知根元素(@XmlRootElement@XmlElementDecl)的XML转换为域对象。有关示例,请参阅:

答案 2 :(得分:1)

根据我在使用XML时发现的,anyType可以表示任何对象,因此最接近它的地方是java.lang.Object。 (除了anyType在技术上可能是一个安全漏洞的事实,允许有人注入任何东西,包括恶意二进制文件到那个位置,并且没有任何东西会阻止它,因为你的架构允许它。)

最好更改架构以允许映射到自定义对象。从编程角度,消费角度和安全角度来看,这都是更清晰的。

等待你不能这样做,我建议将类型存储为元素的属性。您可能需要编写自定义代码然后帮助您将anyType转换回该对象,但至少您知道它的类型。

我的两分钱基于我的经验(主要是在整合领域)。