问题
I am trying to parse a SOAP response. I can show the full response using following line.
System.out.println("Response: " + out.toString());
However when I parse the response and marshall the parsed response, it shows a wrong response.
package-info.java
@XmlSchema(
namespace = "http://v3.hotel.wsapi.ean.com/",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.ean;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
My Code
@XmlRootElement(name="getListResponse")
@XmlAccessorType(XmlAccessType.FIELD)
public class GetListResponse {
@XmlElement(name="HotelListResponse")
private HotelListResponse hotelListResponse;
public GetListResponse() {
this.hotelListResponse = new HotelListResponse();
}
…getter and setter
}
@XmlRootElement(name ="HotelListResponse")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelListResponse {
@XmlElement(name = "customerSessionId")
String customerSessionId;
@XmlElement(name = "numberOfRoomsRequested")
int numberOfRoomsRequested;
@XmlElement(name = "moreResultsAvailable")
boolean moreResultsAvailable;
@XmlElement(name = "cacheKey")
String cacheKey;
@XmlElement(name="cacheLocation")
String cachLocation;
@XmlElement(name = "HotelList")
HotelList hotelList;
public HotelListResponse() {
this.hotelList = new HotelList();
}
… getters and setters…
}
@XmlRootElement(name ="HotelList")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelList {
@XmlAttribute(name = "size")
int size;
@XmlAttribute(name = "activePropertyCount")
int activePropertyCount;
@XmlElement(name = "HotelSummary")
List <HotelSummary> hotelSummaries;
public HotelList() {
this.hotelSummaries = new ArrayList();
}
… getters and setters…
}
@XmlRootElement(name = "HotelSummary")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelSummary {
@XmlAttribute(name = "order")
int order;
@XmlElement(name = "hotelId")
int hotelId;
@XmlElement(name = "name")
String name;
@XmlElement(name = "address1")
String address1;
@XmlElement(name = "city")
String city;
@XmlElement(name = "stateProvinceCode")
String stateProvinceCode;
@XmlElement(name = "postalCode")
int postalCode;
@XmlElement(name = "countryCode")
String countryCode;
@XmlElement(name = "airportCode")
String airportCode;
@XmlElement(name = "supplierType")
String supplierType;
@XmlElement(name = "propertyCategory")
int propertyCategory;
@XmlElement(name = "hotelRating")
float hotelRating;
@XmlElement(name = "confidenceRating")
int confidenceRating;
@XmlElement(name = "amenityMask")
int amenityMask;
@XmlElement(name = "tripAdvisorRating")
float tripAdvisorRating;
@XmlElement(name = "locationDescription")
String locationDescription;
@XmlElement(name = "shortDescription")
String shortDescriptionl; //change amp to &
@XmlElement(name = "highRate")
String highRate;
@XmlElement(name = "lowRate")
float lowRate;
@XmlElement(name = "rateCurrencyCode")
String rateCurrencyCode;
@XmlElement(name = "latitude")
float latitude;
@XmlElement(name = "longitude")
float longitude;
@XmlElement(name = "proximityDistance")
float proximityDistance;
@XmlElement(name = "proximityUnit")
String proximityUnit;
@XmlElement(name = "hotelInDestination")
boolean hotelInDestination;
@XmlElement(name = "thumbNailUrl")
String thumbNailUrl;
@XmlElement(name = "deepLink")
String deepLink;
@XmlElement(name = "RoomRateDetailsList")
RoomRateDetailsList roomRateDetailsList;
public HotelSummary() {
this.roomRateDetailsList = new RoomRateDetailsList();
}
… getters and setters…
}
@XmlRootElement(name = "RoomRateDetailsList")
@XmlAccessorType(XmlAccessType.FIELD)
public class RoomRateDetailsList {
@XmlElement(name="RoomRateDetails")
List<RoomRateDetails> roomRateDetails;
public RoomRateDetailsList() {
this.roomRateDetails = new ArrayList();
}
.. getter and setter..
}
@XmlRootElement(name = "RoomRateDetails")
@XmlAccessorType(XmlAccessType.FIELD)
public class RoomRateDetails {
@XmlElement(name="roomTypeCode")
int roomTypeCode;
@XmlElement(name="rateCode")
int rateCode;
@XmlElement(name="maxRoomOccupancy")
int maxRoomOccupancy;
@XmlElement(name="quotedRoomOccupancy")
int quotedRoomOccupancy;
@XmlElement(name="minGuestAge")
int minGuestAge;
@XmlElement(name="roomDescription")
String roomDescription;
@XmlElement(name="promoId")
int promoId;
@XmlElement(name="promoDescription")
String promoDescription;
@XmlElement(name="currentAllotment")
int currentAllotment;
@XmlElement(name="propertyAvailable")
boolean propertyAvailable;
@XmlElement(name="propertyRestricted")
boolean propertyRestricted;
@XmlElement(name="expediaPropertyId")
int expediaPropertyId;
@XmlElement(name="rateKey")
String rateKey;
@XmlElement(name="RateInfo")
RateInfo rateInfo;
@XmlElement(name="ValueAdds")
ValueAdds valueAdds;
public RoomRateDetails() {
this.rateInfo = new RateInfo();
this.valueAdds = new ValueAdds();
}
… getters and setters…
}
@XmlRootElement(name = "RoomInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class RateInfo {
@XmlAttribute(name="priceBreakdown")
boolean priceBreakdown;
@XmlAttribute(name="promo")
boolean promo;
@XmlAttribute(name="rateChange")
boolean rateChange;
@XmlElement(name="ChargeableRateInfo")
ChargeableRateInfo chargeableRateInfo;
public RateInfo() {
this.chargeableRateInfo = new ChargeableRateInfo();
}
.. getters and setters…
}
@XmlRootElement(name = "ChargeableRateInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class ChargeableRateInfo {
@XmlAttribute(name="averageBaseRate")
float averageBaseRate;
@XmlAttribute(name="averageRate")
float averageRate;
@XmlAttribute(name="commissionableUsdTotal")
float commissionableUsdTotal;
@XmlAttribute(name="currencyCode")
String currencyCode;
@XmlAttribute(name="maxNightlyRate")
float maxNightlyRate;
@XmlAttribute(name="nightlyRateTotal")
float nightlyRateTotal;
@XmlAttribute(name="total")
float total;
@XmlElement(name="NightlyRatesPerRoom")
NightlyRatesPerRoom nightlyRatesPerRoom;
public ChargeableRateInfo() {
this.nightlyRatesPerRoom = new NightlyRatesPerRoom();
}
… getters and setters…
}
@XmlRootElement(name = "NightlyRatesPerRoom")
@XmlAccessorType(XmlAccessType.FIELD)
public class NightlyRatesPerRoom {
@XmlAttribute(name="size")
int size;
@XmlElement(name="NightlyRate")
NightlyRate nightlyRate;
public NightlyRatesPerRoom() {
this.nightlyRate = new NightlyRate();
}
… getters and setters…
}
@XmlRootElement(name = "NightlyRate")
@XmlAccessorType(XmlAccessType.FIELD)
public class NightlyRate {
@XmlAttribute(name="baseRate")
float baseRate;
@XmlAttribute(name="rate")
float rate;
@XmlAttribute(name="promo")
float promo;
public NightlyRate() {
}
… getters and setters…
}
@XmlRootElement(name = "ValueAdds")
@XmlAccessorType(XmlAccessType.FIELD)
public class ValueAdds {
@XmlAttribute(name="size")
private int size;
@XmlElement(name="ValueAdd")
private List<ValueAdd> valueAdd;
public ValueAdds() {
this.valueAdd = new ArrayList();
}
… getters and setters…
}
@XmlRootElement(name = "ValueAdd")
@XmlAccessorType(XmlAccessType.FIELD)
public class ValueAdd {
@XmlAttribute(name="id")
private int id;
@XmlElement(name="description")
private String description;
public ValueAdd() {
}
… getters and setters…
}
Code
try {
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnectionFactory.createConnection();
SOAPFactory soapFactory = SOAPFactory.newInstance();
MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
SOAPHeader header = message.getSOAPHeader();
header.detachNode();
SOAPBody body = message.getSOAPBody();
Name bodyName;
bodyName = soapFactory.createName("getList",
"v3", "http://v3.hotel.wsapi.ean.com/");
SOAPBodyElement getList
= body.addBodyElement(bodyName);
Name childName = soapFactory.createName("HotelListRequest");
SOAPElement HotelListRequest = getList.addChildElement(childName);
……Here, I add child nodes of the request…...
message.writeTo(System.out); //show message details
URL endpoint = new URL("http://dev.api.ean.com/ean-services/ws/hotel/v3");
SOAPMessage response = connection.call(message, endpoint);
connection.close();
SOAPMessage sm = response;
System.err.println("Response:");
ByteArrayOutputStream out = new ByteArrayOutputStream();
sm.writeTo(out);
System.err.println(">>>" + out.toString());
System.err.println(">>>>>>>>>>>parse:");
SOAPBody sb = response.getSOAPBody();
DOMSource source = new DOMSource(sb);
HotelListResponse results = new HotelListResponse();
results = (HotelListResponse) JAXB.unmarshal(source, HotelListResponse.class);
JAXBContext context = JAXBContext.newInstance(HotelListResponse.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
System.err.println("Response *******");
m.marshal(results, System.out);
System.err.println("116872:" + results.getHotelList().getHotelSummaries().get(0).getHotelId());
} catch (Exception ex) {
ex.printStackTrace();
}
Actual Respose
Response:
Response:>>><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getListResponse xmlns:ns2="http://v3.hotel.wsapi.ean.com/">
<HotelListResponse>
<customerSessionId>0ABAAA95-28B2-5914-7952-0331AC9069EA</customerSessionId>
<numberOfRoomsRequested>1</numberOfRoomsRequested>
<moreResultsAvailable>true</moreResultsAvailable>
<cacheKey>-41118b29:146950321ac:-69e1</cacheKey>
<cacheLocation>10.176.160.143:7300</cacheLocation>
<HotelList size="25" activePropertyCount="119">
<HotelSummary order="0">
<hotelId>150241</hotelId>
<name>Rydges World Square</name>
<address1>389 Pitt Street</address1>
<city>Sydney</city>
<stateProvinceCode>NW</stateProvinceCode>
<postalCode>2000</postalCode>
<countryCode>AU</countryCode>
<airportCode>SYD</airportCode>
<supplierType>E</supplierType>
<propertyCategory>1</propertyCategory>
<hotelRating>4.5</hotelRating>
<confidenceRating>52</confidenceRating>
<amenityMask>1343491</amenityMask>
<tripAdvisorRating>3.5</tripAdvisorRating>
<locationDescription>Near Darling Harbour</locationDescription>
<shortDescription>&lt;p&gt;&lt;b&gt;Property Location&lt;/b&gt; &lt;br /&gt;With a stay at Rydges World Square, you&apos;ll be centrally located in Sydney, steps from World Square Shopping Centre and minutes from Capitol Theatre. This 4.5-star</shortDescription>
<highRate>218.64</highRate>
<lowRate>218.64</lowRate>
<rateCurrencyCode>USD</rateCurrencyCode>
<latitude>-33.8766</latitude>
<longitude>151.20752</longitude>
<proximityDistance>0.5492472</proximityDistance>
<proximityUnit>MI</proximityUnit>
<hotelInDestination>true</hotelInDestination>
<thumbNailUrl>/hotels/1000000/570000/565000/564969/564969_91_t.jpg</thumbNailUrl>
<deepLink>http://travel.ian.com/index.jsp?pageName=hotAvail&amp;cid=55505&amp;hotelID=150241&amp;mode=2&amp;numberOfRooms=1&amp;room-0-adult-total=2&amp;room-0-child-total=0&amp;arrivalMonth=5&amp;arrivalDay=18&amp;departureMonth=5&amp;departureDay=19&amp;showInfo=true&amp;locale=en_US&amp;currencyCode=USD</deepLink>
<RoomRateDetailsList>
<RoomRateDetails>
<roomTypeCode>200156055</roomTypeCode>
<rateCode>202768754</rateCode>
<maxRoomOccupancy>2</maxRoomOccupancy>
<quotedRoomOccupancy>2</quotedRoomOccupancy>
<minGuestAge>0</minGuestAge>
<roomDescription>Special: Deluxe King - Check-In from 8:30pm</roomDescription>
<promoId>201528081</promoId>
<promoDescription>Sale! Save 25% on this Stay.</promoDescription>
<currentAllotment>10</currentAllotment>
<propertyAvailable>true</propertyAvailable>
<propertyRestricted>false</propertyRestricted>
<expediaPropertyId>564969</expediaPropertyId>
<rateKey>0ABAAA85-18B2-9914-6952-0351AC9069DF</rateKey>
<RateInfo priceBreakdown="true" promo="true" rateChange="false">
<ChargeableRateInfo averageBaseRate="218.64" averageRate="218.64" commissionableUsdTotal="218.64" currencyCode="USD" maxNightlyRate="218.64" nightlyRateTotal="218.64" total="218.64">
<NightlyRatesPerRoom size="1">
<NightlyRate baseRate="218.64" rate="218.64" promo="false"/>
</NightlyRatesPerRoom>
</ChargeableRateInfo>
</RateInfo>
<ValueAdds size="1">
<ValueAdd id="2048">
<description>Free Wireless Internet</description>
</ValueAdd>
</ValueAdds>
</RoomRateDetails>
<RoomRateDetails>
...
>>>>>>>>>>>parse:
Response *******
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<HotelListResponse xmlns="http://v3.hotel.wsapi.ean.com/">
<numberOfRoomsRequested>0</numberOfRoomsRequested>
<moreResultsAvailable>false</moreResultsAvailable>
<HotelList size="0" activePropertyCount="0"/>
</HotelListResponse>
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:635)
at java.util.ArrayList.get(ArrayList.java:411)
at com.expedia.Engine.retrieveHotels(Engine.java:135)
at com.hotelsdotcom.App.main(App.java:17)
回答1:
How to Fix Things
Unmarshal at the Right Level
Currently you are unmarshalling the XML node that corresponds to the soap:Body
element, instead you need to navigate down to the HotelListResponse
element and unmarshal that.
You could try the following:
DOMSource source = new DOMSource(sb.getFirstChild().getFirstChild());
Watch your Namespace Qualification
In the XML that you have marshalled all the elements appear qualified with the http://v3.hotel.wsapi.ean.com/
, the document that you are trying to unmarshal doesn't have this namespace qualification so you should remove the @XmlSchema
annotation from the package-info
class.
Use Unmarshaller
instead of JAXB.unmarshal
Instead of doing the following:
results = (HotelListResponse) JAXB.unmarshal(source, HotelListResponse.class);
I would recommend doing:
JAXBContext jc = JAXBContext.newInstance(HotelListResponse.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
results = unmarshaller.unmarshal(source, HotelListResponse.class).getValue();
What is Happening Now
When you use an unmarshal
method that takes a class parameter, you are telling JAXB what class that XML corresponds to instead of having it automatically determined by the root element.
results = (HotelListResponse) JAXB.unmarshal(source, HotelListResponse.class)
Because the level of the XML document is wrong JAXB isn't able to match any of it to your domain model. Therefore only the default values are populated. This is why the result is full of values that are 0
or false
.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<HotelListResponse xmlns="http://v3.hotel.wsapi.ean.com/">
<numberOfRoomsRequested>0</numberOfRoomsRequested>
<moreResultsAvailable>false</moreResultsAvailable>
<HotelList size="0" activePropertyCount="0"/>
</HotelListResponse>
来源:https://stackoverflow.com/questions/24131822/parsed-soap-response-is-different-with-the-received-response