无法解组SOAP响应

时间:2014-05-22 12:18:55

标签: java soap jaxb unmarshalling stringreader

我可以发送请求并收到回复,但我无法解析回复。它返回以下错误:

Local Name:Body
error is here
java.lang.NullPointerException
    at com.ticketmaster.ticketmaster.TicketMaster.Search(TicketMaster.java:119)
    at com.ticketmaster.ticketmaster.App.main(App.java:12)

代码

    SOAPMessage response
            = connection.call(message, endpoint);

    connection.close();
        SOAPMessage sm = response;
        SOAPBody sb = response.getSOAPBody();
        System.err.println("Node Name:" + sb.getNodeName());  //return nothing
        System.err.println("Local Name:" + sb.getLocalName());  //return Local Name:Body

        DOMSource source = new DOMSource(sb);
        results = (FindEventsResponse) JAXB.unmarshal(source, FindEventsResponse.class);
        System.err.println("Results size: " + this.results.returnTag.results.item.get(0).getName());

} catch (Exception ex) {
    System.err.println("error is here");
    ex.printStackTrace();
}

响应:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                   xmlns:ns1="http://ticketmaster.productserve.com/v2/soap.php" 
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
                   SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Body>
        <ns1:findEventsResponse>
            <return xsi:type="ns1:Response">
                <details xsi:type="ns1:Details">
                    <totalResults xsi:type="xsd:int">20662</totalResults>
                    <totalPages xsi:type="xsd:int">414</totalPages>
                    <currentPage xsi:type="xsd:int">1</currentPage>
                    <resultsPerPage xsi:type="xsd:int">50</resultsPerPage>
                </details>
                <results SOAP-ENC:arrayType="ns1:Event[50]" xsi:type="ns1:ArrayOfEvent">
                    <item xsi:type="ns1:Event">
                        <eventId xsi:type="xsd:int">1516682</eventId>
                        <ticketmasterEventId xsi:type="xsd:string">18004C6E8D7218A8</ticketmasterEventId>
                        <status xsi:type="xsd:string">onSale</status>
                        <name xsi:type="xsd:string">The Art of the Brick</name>
                        <url xsi:type="xsd:string">http://www.ticketmaster.ie/event/18004C6E8D7218A8?camefrom=CFC_UK_BUYAT&amp;brand=[=BRAND=]</url>
                        <eventDate xsi:type="xsd:string">2014-05-23 10:00:00</eventDate>
                        <onSaleDate xsi:type="xsd:string">0000-00-00 00:00:00</onSaleDate>
                        <preSaleDate xsi:type="xsd:string">0000-00-00 00:00:00</preSaleDate>
                        <category xsi:type="xsd:string">Exhibitions</category>
                        <categoryId xsi:type="xsd:int">754</categoryId>
                        <parentCategory xsi:type="xsd:string">Family &amp;amp; Attractions</parentCategory>
                        <parentCategoryId xsi:type="xsd:int">10003</parentCategoryId>
                        <minPrice xsi:type="xsd:float">17</minPrice>
                        <maxPrice xsi:type="xsd:float">17</maxPrice>
                        <artists SOAP-ENC:arrayType="ns1:Artist[1]" xsi:type="ns1:ArrayOfArtist">
                            <item xsi:type="ns1:Artist">
                                <artistId xsi:type="xsd:int">1806028</artistId>
                                <ticketmasterArtistId xsi:type="xsd:int">1663495</ticketmasterArtistId>
                                <name xsi:type="xsd:string">The Art of the Brick</name>
                                <url xsi:type="xsd:string">http://www.ticketmaster.co.uk/The-Art-of-the-Brick-tickets/artist/1663495?camefrom=CFC_UK_BUYAT&amp;brand=[=BRAND=]</url>
                                <imageUrl xsi:type="xsd:string">http://media.ticketmaster.com/tm/en-us/tmimages/TM_GenCatImgs_Generic_BW.jpg</imageUrl>
                                <category xsi:type="xsd:string">Miscellaneous</category>
                                <categoryId xsi:type="xsd:int">0</categoryId>
                                <parentCategory xsi:type="xsd:string">Miscellaneous</parentCategory>
                                <parentCategoryId xsi:type="xsd:int">10005</parentCategoryId>
                            </item>
                        </artists>
                        <venue xsi:type="ns1:Venue">
                            <venueId xsi:type="xsd:int">3331</venueId>
                            <ticketmasterVenueId xsi:type="xsd:int">198292</ticketmasterVenueId>
                            <name xsi:type="xsd:string">Ambassador Theatre</name>
                            <street xsi:type="xsd:string">Oconnell Street</street>
                            <city xsi:type="xsd:string">Dublin</city>
                            <country xsi:type="xsd:string">United Kingdom</country>
                            <postcode xsi:type="xsd:string">Dublin 1</postcode>
                            <url xsi:type="xsd:string">http://www.ticketmaster.ie/Ambassador-Theatre-tickets-Dublin/venue/198292?camefrom=CFC_UK_BUYAT&amp;brand=</url>
                            <imageUrl xsi:type="xsd:string">http://media.ticketmaster.co.uk/tmimages/TM_GenVenueImg_BW.jpg</imageUrl>
                            <state xsi:type="xsd:string"></state>
                        </venue>
                    </item>
                    <item xsi:type="ns1:Event">
                     ....

模型类

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class FindEventsResponse {
    @XmlElement(name = "return")
    Return returnTag;

    public FindEventsResponse() {
       this.returnTag = new Return();
    }
    getter and setter

}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Return {
    @XmlElement(name = "details")
    Details details;
    @XmlElement(name = "results")
    Results results;

    public Return(Details details, Results results) {
       this.details = new Details();
       this.results = new Results();
    }
    getters and setters


}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Details {

    @XmlElement(name = "totalResults")
    int totalResults;
    @XmlElement(name = "totalPages")
    int totalPages;
    @XmlElement(name = "currentPage")
    int currentPage;
    @XmlElement(name = "resultPerPage")
    int resultsPerPage;

     getters and setters

}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Results {
    @XmlElement(name = "item")
    List<Item> item;

    public Results() {
       this.item = new ArrayList();
    }
    getter and setter



}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Item {

    @XmlElement(name = "eventId")
    int eventId;
    @XmlElement(name = "ticketmasterEventId")
    String ticketmasterEventId;
    @XmlElement(name = "status")
    String status;
    @XmlElement(name = "name")
    String name;
    @XmlElement(name = "url")
    String url;
    @XmlElement(name = "eventDate")
    String eventDate;
    @XmlElement(name = "onSaleDate")
    String onSaleDate;
    @XmlElement(name = "preSaleDate")
    String preSaleDate;
    @XmlElement(name = "category")
    String category;
    @XmlElement(name = "categoryId")
    int categoryId;
    @XmlElement(name = "parentCategory")
    String parentCategory;
    @XmlElement(name = "parentCategoryId")
    int parentCategoryId;
    @XmlElement(name = "minPrice")
    int minPrice;
    @XmlElement(name = "maxPrice")
    int maxPrice;
    @XmlElement(name = "artists")
    private Artists artist;
    @XmlElement(name = "venue")
    private Venue venue;

    public Item() {
       this.artist = new Artists();
       this.venue = new Venue();
    }

    getters and setters

}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Artists {
    @XmlElement(name = "artists")
    private ArtistItem item;

    public Artists() {
        this.item = new ArtistItem();
    }
    getter and setter
}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ArtistItem {

    @XmlElement(name = "artistId")
    int artistId;
    @XmlElement(name = "ticketmasterArtistsId")
    int ticketmasterArtistId;
    @XmlElement(name = "name")
    String name;
    @XmlElement(name = "url")
    String url;
    @XmlElement(name = "imageUrl")
    String imageUrl;
    @XmlElement(name = "category")
    String category;
    @XmlElement(name = "categoryId")
    int categoryId;
    @XmlElement(name = "parentCategory")
    String parentCategory;
    @XmlElement(name = "parentCategoryId")
    int parentCategoryId;

    getters and setters
}

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Venue {

    @XmlElement(name = "venueId")
    int venueId;
    @XmlElement(name = "ticketmasterVenueId")
    int ticketmasterVenueId;
    @XmlElement(name = "name")
    String name;
    @XmlElement(name = "street")
    String street;
    @XmlElement(name = "city")
    String city;
    @XmlElement(name = "country")
    String country;
    @XmlElement(name = "postcode")
    String postcode;
    @XmlElement(name = "url")
    String url;
    @XmlElement(name = "imageUrl")
    String imageUrl;
    @XmlElement(name = "state")
    String state;

    getters and setters
}

根据以下其中一个答案,我整理了结果并显示错误的答案。

package-info.java

@XmlSchema( 
    namespace = "http://ticketmaster.productserve.com/v2/soap.php",
    elementFormDefault = XmlNsForm.UNQUALIFIED) 
package com.ticketmaster.ticketmaster;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

代码

    SOAPBody sb = response.getSOAPBody();
System.err.println(">>"+ sb.getFirstChild().getNodeName());
Iterator itr = sb.getChildElements();
while(itr.hasNext()){
    Object element = itr.next();
    System.err.println(element + " ");
}
Document d = sb.extractContentAsDocument();
System.err.println("result of d:"+d.getTextContent());
DOMSource source = new DOMSource(d);
results = (FindEventsResponse) JAXB.unmarshal(source, FindEventsResponse.class);
System.err.println("results>"+results.getReturnTag().getResults().getItem().get(0).getName());

错误

.....
><city xsi:type="xsd:string">London</city><country xsi:type="xsd:string">United Kingdom</country><postcode xsi:type="xsd:string">SE1 8XX</postcode><url xsi:type="xsd:string">http://www.ticketmaster.co.uk/The-London-Wonderground-tickets-London/venue/253993?camefrom=CFC_UK_BUYAT&amp;brand=</url><imageUrl xsi:type="xsd:string">http://media.ticketmaster.co.uk/tmimages/TM_GenVenueImg_BW.jpg</imageUrl><state xsi:type="xsd:string"></state></venue></item></results></return></ns1:findEventsResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

>>ns1:findEventsResponse
[ns1:findEventsResponse: null] 
result of d:null
error is here

java.lang.IllegalArgumentException: prefix xsd is not bound to a namespace
    at com.sun.xml.internal.bind.DatatypeConverterImpl._parseQName(DatatypeConverterImpl.java:346)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.selectLoader(LeafPropertyXsiLoader.java:75)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.startElement(LeafPropertyXsiLoader.java:58)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:486)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:229)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:266)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:235)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:266)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:235)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:266)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:235)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:266)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:235)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:112)
    at com.sun.xml.internal.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:95)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:312)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:288)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:238)
    at javax.xml.bind.JAXB.unmarshal(JAXB.java:259)
    at com.ticketmaster.ticketmaster.TicketMaster.Search(TicketMaster.java:132)
    at com.ticketmaster.ticketmaster.App.main(App.java:12)   

1 个答案:

答案 0 :(得分:9)

确保你正在解组纠正的事情

您需要解组 SOAP正文所保留的内容,而不是整个 SOAP消息。下面是代码的样子:

SOAPMessage sm = response;
SOAPBody sb = response.getSOAPBody();
Document d = sb.extractContentAsDocument();
DOMSource source = new DOMSource(d);
results = (FindEventsResponse) JAXB.unmarshal(source, FindEventsResponse.class);

sb.extractContentAsDocument的结果将是一个等同于以下内容的DOM:

<?xml version="1.0" encoding="UTF-8"?>
<ns1:findEventsResponse xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:ns1="http://ticketmaster.productserve.com/v2/soap.php"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <return xsi:type="ns1:Response">
        <details xsi:type="ns1:Details">
            <totalResults xsi:type="xsd:int">20662</totalResults>
            <totalPages xsi:type="xsd:int">414</totalPages>
            <currentPage xsi:type="xsd:int">1</currentPage>
            <resultsPerPage xsi:type="xsd:int">50</resultsPerPage>
        </details>
        <results SOAP-ENC:arrayType="ns1:Event[50]" xsi:type="ns1:ArrayOfEvent">
            <item xsi:type="ns1:Event">
                <eventId xsi:type="xsd:int">1516682</eventId>
                <ticketmasterEventId xsi:type="xsd:string">18004C6E8D7218A8</ticketmasterEventId>
                <status xsi:type="xsd:string">onSale</status>
                <name xsi:type="xsd:string">The Art of the Brick</name>
                <url xsi:type="xsd:string">http://www.ticketmaster.ie/event/18004C6E8D7218A8?camefrom=CFC_UK_BUYAT&amp;brand=[=BRAND=]</url>
                <eventDate xsi:type="xsd:string">2014-05-23 10:00:00</eventDate>
                <onSaleDate xsi:type="xsd:string">0000-00-00 00:00:00</onSaleDate>
                <preSaleDate xsi:type="xsd:string">0000-00-00 00:00:00</preSaleDate>
                <category xsi:type="xsd:string">Exhibitions</category>
                <categoryId xsi:type="xsd:int">754</categoryId>
                <parentCategory xsi:type="xsd:string">Family &amp;amp; Attractions</parentCategory>
                <parentCategoryId xsi:type="xsd:int">10003</parentCategoryId>
                <minPrice xsi:type="xsd:float">17</minPrice>
                <maxPrice xsi:type="xsd:float">17</maxPrice>
                <artists SOAP-ENC:arrayType="ns1:Artist[1]" xsi:type="ns1:ArrayOfArtist">
                    <item xsi:type="ns1:Artist">
                        <artistId xsi:type="xsd:int">1806028</artistId>
                        <ticketmasterArtistId xsi:type="xsd:int">1663495</ticketmasterArtistId>
                        <name xsi:type="xsd:string">The Art of the Brick</name>
                        <url xsi:type="xsd:string">http://www.ticketmaster.co.uk/The-Art-of-the-Brick-tickets/artist/1663495?camefrom=CFC_UK_BUYAT&amp;brand=[=BRAND=]</url>
                        <imageUrl xsi:type="xsd:string">http://media.ticketmaster.com/tm/en-us/tmimages/TM_GenCatImgs_Generic_BW.jpg</imageUrl>
                        <category xsi:type="xsd:string">Miscellaneous</category>
                        <categoryId xsi:type="xsd:int">0</categoryId>
                        <parentCategory xsi:type="xsd:string">Miscellaneous</parentCategory>
                        <parentCategoryId xsi:type="xsd:int">10005</parentCategoryId>
                    </item>
                </artists>
                <venue xsi:type="ns1:Venue">
                    <venueId xsi:type="xsd:int">3331</venueId>
                    <ticketmasterVenueId xsi:type="xsd:int">198292</ticketmasterVenueId>
                    <name xsi:type="xsd:string">Ambassador Theatre</name>
                    <street xsi:type="xsd:string">Oconnell Street</street>
                    <city xsi:type="xsd:string">Dublin</city>
                    <country xsi:type="xsd:string">United Kingdom</country>
                    <postcode xsi:type="xsd:string">Dublin 1</postcode>
                    <url xsi:type="xsd:string">http://www.ticketmaster.ie/Ambassador-Theatre-tickets-Dublin/venue/198292?camefrom=CFC_UK_BUYAT&amp;brand=</url>
                    <imageUrl xsi:type="xsd:string">http://media.ticketmaster.co.uk/tmimages/TM_GenVenueImg_BW.jpg</imageUrl>
                    <state xsi:type="xsd:string"></state>
                </venue>
            </item>
            <item xsi:type="ns1:Event"></item>
        </results>
    </return>
</ns1:findEventsResponse>

更新

根据您获得的新例外情况:

java.lang.IllegalArgumentException: prefix xsd is not bound to a namespace
    at com.sun.xml.internal.bind.DatatypeConverterImpl._parseQName(DatatypeConverterImpl.java:346)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.selectLoader(LeafPropertyXsiLoader.java:75)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.startElement(LeafPropertyXsiLoader.java:58)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:486)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)

好像sb.extractContentAsDocument();没有带来SOAP消息中的xmlns:xsd声明。相反,您可以更改代码以执行以下操作:

SOAPMessage sm = response;
SOAPBody sb = response.getSOAPBody();
DOMSource source = new DOMSource(sb.getFirstChild());
results = (FindEventsResponse) JAXB.unmarshal(source, FindEventsResponse.class);

确保正确映射命名空间限定

具有以下内容告诉JAXB,映射到没有显式指定的命名空间的XML元素的所有内容都应属于http://ticketmaster.productserve.com/v2/soap.php命名空间。

@XmlSchema( 
    namespace = "http://ticketmaster.productserve.com/v2/soap.php",
    elementFormDefault = XmlNsForm.QUALIFIED) 
package com.ticketmaster.ticketmaster;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

在XML中,只有findEventsResponse元素是名称空间限定的。这意味着您的注释应该是以下内容(注意从QUALIFIED更改为UNQUALIFIED):

@XmlSchema( 
    namespace = "http://ticketmaster.productserve.com/v2/soap.php",
    elementFormDefault = XmlNsForm.UNQUALIFIED) 
package com.ticketmaster.ticketmaster;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

演示代码

将上述XML用作input.xml我能够解组和编组模型,因为您已使用上述@XmlSchema修复在问题中对其进行了定义。

import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(FindEventsResponse.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StreamSource xml = new StreamSource("src/forum23806625/input.xml");
        JAXBElement<FindEventsResponse> response = unmarshaller.unmarshal(xml, FindEventsResponse.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(response, System.out);
    }

}