Java 无法解组 SOAP 响应

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23806625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 01:17:18  来源:igfitidea点击:

Can not unmarshall the SOAP response

javasoapjaxbunmarshallingstringreader

提问by J888

I could send a request and receive the response but I can not parse the response. It returns the following error:

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

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)

Code

代码

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

Response:

回复:

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

Model Classes

模型类

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

Based on one of the following answers, I marshalled the result and it shows a wrong response.

根据以下答案之一,我整理了结果并显示了错误的响应。

package-info.java

包信息.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;

Code

代码

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

Error is

错误是

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

采纳答案by bdoughan

Ensure You Are Unmarshalling the Correct Thing

确保您正在解组正确的东西

You need to unmarshal the content held onto by SOAP body, not the entire SOAP message. Below is what the code might look like:

您需要解组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);

The result of sb.extractContentAsDocumentis going to be a DOM that is equivalent to the following:

的结果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>

UPDATE

更新

Based on the new exception you are getting:

根据您获得的新异常:

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)

It appears as though sb.extractContentAsDocument();is not bringing along the xmlns:xsddeclaration from the SOAP message. Instead you can change the code to do the following:

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

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

Ensure the Namespace Qualification is Mapped Correctly

确保正确映射命名空间资格

Having the following tells JAXB that everything mapped to an XML element without an explicitly specified namespace should belong in the http://ticketmaster.productserve.com/v2/soap.phpnamespace.

具有以下内容告诉 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;

In your XML only the findEventsResponseelement is namespace qualified. This means your annotation should be the following instead (note change from QUALIFIEDto UNQUALIFIED):

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

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

Demo Code

演示代码

Using the above XML as input.xmlI was able to unmarshal and marshal the model as you have defined it in your question with the @XmlSchemafix mentioned above.

使用上面的 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);
    }

}