无法使用 JAXB 解析响应

Cannot parse response with JAXB

我正在尝试发送 REST 请求并解析响应,但它 returns NullPointerException。我认为问题出在命名空间上。 当我有 package-info.java 文件时,它 returns NullPointerException 而当我没有它时 returns 以下:

Exception in thread "main"     
org.springframework.http.converter.HttpMessageNotReadableException: 
Could not unmarshal to [class com.expedia.HotelListResponse]: unexpected 
element (uri:"http://v3.hotel.wsapi.ean.com/", local:"HotelListResponse"). 
Expected elements are <{}ChargeableRateInfo>,<{}HotelList>,
<{}HotelListResponse>,<{}HotelSummary>,<{}NightlyRate>,
<{}NightlyRatesPerRoom>,<{}RateInfo>,<{}RoomRateDetails>,
<{}RoomRateDetailsList>,<{}Surcharge>,<{}Surcharges>,<{}ValueAdd>,
<{}ValueAdds>; nested exception is javax.xml.bind.UnmarshalException: 
unexpected element (uri:"http://v3.hotel.wsapi.ean.com/", 
local:"HotelListResponse"). Expected elements are <{}ChargeableRateInfo>,
<{}HotelList>,<{}HotelListResponse>,<{}HotelSummary>,<{}NightlyRate>,
<{}NightlyRatesPerRoom>,<{}RateInfo>,<{}RoomRateDetails>,
<{}RoomRateDetailsList>,<{}Surcharge>,<{}Surcharges>,<{}ValueAdd>,
<{}ValueAdds>

如果我删除 package-infoqualified 部分,代码显示如下:

>>>0ABD9-732-A12-124-2BE4FD21A
>>>1

nullPointerException
....

部分响应示例

<ns2:HotelListResponse>
    <customerSessionId>0ABD9-732-A12-124-2BE4FD21A
    </customerSessionId>
    <numberOfRoomsRequested>1</numberOfRoomsRequested>
    <moreResultsAvailable>true</moreResultsAvailable>
    <cacheKey>168951a:159922be3fd:-11ce</cacheKey>
    <cacheLocation>19.11.13.19:7300</cacheLocation>
    <HotelList size="20" activePropertyCount="1231">
        <HotelSummary order="0">
            <hotelId>335698</hotelId>
            <name>Park Plaza Westminster Bridge London</name>
            <address1>200 Westminster Bridge Road</address1>
            <city>London</city>
            <postalCode>SE1 7UT</postalCode>
            <countryCode>GB</countryCode>
            <airportCode>LCY</airportCode>
            <supplierType>E</supplierType>
            <propertyCategory>1</propertyCategory>
            <hotelRating>4.0</hotelRating>
            <confidenceRating>45</confidenceRating>
            <amenityMask>1511947</amenityMask>
            <locationDescription>Near London Aquarium</locationDescription>
            <shortDescription>&lt;p&gt;&lt;b&gt;Property Location&lt;/b&gt;
                &lt;br /&gt;A stay at Park Plaza Westminster Bridge London places
                you in the heart of London, steps from London Aquarium and London
                Dungeon. This 4-star hotel is close to</shortDescription>
            <highRate>314.27</highRate>
            <lowRate>254.35</lowRate>
            <rateCurrencyCode>USD</rateCurrencyCode>
            <latitude>51.50111</latitude>
            <longitude>-0.11733</longitude>
            <proximityDistance>0.7890795</proximityDistance>
            <proximityUnit>MI</proximityUnit>
            <hotelInDestination>true</hotelInDestination>
            <thumbNailUrl>/hotels/4000000/3120000/3113100/3113039/3113039_31_t.jpg
            </thumbNailUrl>
            <deepLink>http://www.travelnow.com/templates/441384/hotels/335698/overview?lang=en&amp;currency=USD&amp;standardCheckin=11/23/2016&amp;standardCheckout=11/25/2016&amp;roomsCount=1&amp;rooms[0].adultsCount=1
            </deepLink>
            <RoomRateDetailsList>
                <RoomRateDetails>
                    <roomTypeCode>200750627</roomTypeCode>
                    <rateCode>203729567</rateCode>
                    <maxRoomOccupancy>2</maxRoomOccupancy>
                    <quotedRoomOccupancy>1</quotedRoomOccupancy>
                    <minGuestAge>0</minGuestAge>
                    <roomDescription>Superior Twin Room, 2 Single Beds
                    </roomDescription>
                    <promoId>209171300</promoId>
                    <promoDescription>Save 15%</promoDescription>
                    <currentAllotment>9</currentAllotment>
                    <propertyAvailable>true</propertyAvailable>
                    <propertyRestricted>false</propertyRestricted>
                    <expediaPropertyId>3113039</expediaPropertyId>
                    <rateKey>81300a5d-b697-457e-a059-2c22f6ce389b</rateKey>
                    <RateInfo priceBreakdown="true" promo="true" rateChange="true">
                        <ChargeableRateInfo averageBaseRate="263.30"
                            averageRate="217.28" commissionableUsdTotal="521.48"
                            currencyCode="USD" maxNightlyRate="222.61" nightlyRateTotal="434.57"
                            surchargeTotal="86.91" total="521.48">
                            <NightlyRatesPerRoom size="2">
                                <NightlyRate baseRate="269.75" rate="222.61" promo="true" />
                                <NightlyRate baseRate="256.84" rate="211.96" promo="true" />
                            </NightlyRatesPerRoom>
                            <Surcharges size="1">
                                <Surcharge type="TaxAndServiceFee" amount="86.91" />
                            </Surcharges>
                        </ChargeableRateInfo>
                    </RateInfo>
                    <ValueAdds size="1">
                        <ValueAdd id="2048">
                            <description>Free Wireless Internet</description>
                        </ValueAdd>
                    </ValueAdds>
                </RoomRateDetails>
            </RoomRateDetailsList>
        </HotelSummary>
        <HotelSummary order="1">

请求

final String URL = "http://api.ean.com/ean-services/rs/hotel/v3/list?cid="+CID+ "&apikey=" +API_KEY +"&sig= " + sig + "&apiExperience=PARTNER_WEBSITE&arrivalDate=12/11/2016&departureDate=12/18/2016&room1=1&city=London&stateProvinceCode=LN&countryCode=UK";
        System.err.println("URL:" + URL);
        RestTemplate restTemplate = new RestTemplate();
        HotelListResponse hotelResponse = restTemplate.getForObject(URL,HotelListResponse.class);
        System.err.println(">>>" + hotelResponse.getCacheKey());
        System.err.println(">>>" + hotelResponse.getNumberOfRoomsRequested());
        System.err.println(" Hotel Summaries Size>>>" + hotelResponse.getHotelList().getHotelSummaries().size());

包-info.java

@XmlSchema( 
    namespace = "http://v3.hotel.wsapi.ean.com/", 
    elementFormDefault = XmlNsForm.QUALIFIED) 
package com.expedia;

import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

HotelListResponse

@XmlRootElement(name = "HotelListResponse")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelListResponse {
    @XmlElement(name = "customerSessionId")
    private String customerSessionId;
    @XmlElement(name = "numberOfRoomsRequested")
    private short numberOfRoomsRequested;
    @XmlElement(name = "moreResultsAvailable")
    private boolean moreResultsAvailable;
    @XmlElement(name = "cacheKey")
    private String cacheKey;
    @XmlElement(name = "cacheLocation")
    private String cacheLocation;
    @XmlElement(name = "hotelList")
    private HotelList hotelList;

    getters and setters go here

酒店列表

@XmlRootElement(name="HotelList")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelList {
    @XmlAttribute(name="size")
    private int size;
    @XmlAttribute(name="activePropertyCount")
    private int activePropertyCount;
    private List<HotelSummary> hotelSummaries;

    getters and setters go here

酒店总结

@XmlRootElement(name="HotelSummary")
@XmlAccessorType(XmlAccessType.FIELD)
public class HotelSummary {
    @XmlAttribute(name="order")
    private int order;
    @XmlElement(name="hotelId")
    private int hotelId;
    @XmlElement(name="name")
    private String name;
    @XmlElement(name="address1")
    private String address1;
    @XmlElement(name="city")
    private String city;
    @XmlElement(name="stateProvinceCode")
    private String stateProvinceCode;
    @XmlElement(name="postalCode")
    private int postalCode;
    @XmlElement(name="countryCode")
    private String countryCode;
    @XmlElement(name="airportCode")
    private String airportCode;
    @XmlElement(name="supplierType")
    private String supplierType;
    @XmlElement(name="propertyCategory")
    private int propertyCategory;
    @XmlElement(name="hotelRating")
    private float hotelRating;
    @XmlElement(name="confidenceRating")
    private int confidenceRating;
    @XmlElement(name="amenityMask")
    private int amenityMask;
    @XmlElement(name="locationDescription")
    private String locationDescription;
    @XmlElement(name="shortDescription")
    private String shortDescription;
    @XmlElement(name="highRate")
    private double highRate;
    @XmlElement(name="lowRate")
    private double lowRate;
    @XmlElement(name="rateCurrencyCode")
    private String rateCurrencyCode;
    @XmlElement(name="latitude")
    private double latitude;
    @XmlElement(name="longitude")
    private double longitude;
    @XmlElement(name="proximityDistance")
    private double proximityDistance;
    @XmlElement(name="proximityUnit")
    private String proximityUnit;
    @XmlElement(name="hotelInDestination")
    private boolean hotelInDestination;
    @XmlElement(name="thumbNailUrl")
    private String thumbNailUrl;
    @XmlElement(name="deepLink")
    private String deepLink;
    @XmlElement(name="RoomRateDetailsList")
    private RoomRateDetailsList roomRateDetailsList;


    getters and setters go here

RoomRateDetailsList

@XmlRootElement(name = "RoomRateDetailsList")
@XmlAccessorType(XmlAccessType.FIELD)
public class RoomRateDetailsList {
    @XmlElement(name = "RoomRateDetails")
    private RoomRateDetails roomRateDetails;

    getters and setters go here

房价详情

@XmlRootElement(name = "RoomRateDetails")
@XmlAccessorType(XmlAccessType.FIELD)
public class RoomRateDetails {
    @XmlElement(name = "roomTypeCode")
    private int roomTypeCode;
    @XmlElement(name = "rateCode")
    private int rateCode;
    @XmlElement(name = "maxRoomOccupancy")
    private int maxRoomOccupancy;
    @XmlElement(name = "quotedRoomOccupancy")
    private int quotedRoomOccupancy;
    @XmlElement(name = "minGuestAge")
    private int minGuestAge;
    @XmlElement(name = "roomDescription")
    private String roomDescription;
    @XmlElement(name = "currentAllotment")
    private int currentAllotment;
    @XmlElement(name = "propertyAvailable")
    private boolean propertyAvailable;
    @XmlElement(name = "propertyRestricted")
    private boolean propertyRestricted;
    @XmlElement(name = "expediaPropertyId")
    private int expediaPropertyId;
    @XmlElement(name = "rateKey")
    private String rateKey;
    @XmlElement(name="RateInfo")
    private RateInfo rateInfo;
    @XmlElement(name="ValueAdds")
    private ValueAdds valueAdds;

    getters and setters go here

汇率信息

@XmlRootElement(name="RateInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class RateInfo {
    @XmlAttribute(name="priceBreakdown")
    private boolean priceBreakdown;
    @XmlAttribute(name="promo")
    private boolean promo;
    @XmlAttribute(name="rateChange")
    private boolean rateChange;
    @XmlElement(name="ChargeableRateInfo")
    private ChargeableRateInfo chargeableRateInfo;

    getters and setters go here

ChargeableRateInfo

@XmlRootElement(name = "ChargeableRateInfo")
@XmlAccessorType(XmlAccessType.FIELD)
public class ChargeableRateInfo {
    @XmlAttribute(name = "averageBaseRate")
    private double averageBaseRate;
    @XmlAttribute(name = "averageRate")
    private double averageRate;
    @XmlAttribute(name = "commissionableUsdTotal")
    private double commissionableUsdTotal;
    @XmlAttribute(name = "currencyCode")
    private String currencyCode;
    @XmlAttribute(name = "maxNightlyRate")
    private double maxNightlyRate;
    @XmlAttribute(name = "nightlyRateTotal")
    private double nightlyRateTotal;
    @XmlAttribute(name = "surchargeTotal")
    private double surchargeTotal;
    @XmlAttribute(name = "total")
    private double total;
    @XmlElement(name = "NightlyRatesPerRoom")
    private NightlyRatesPerRoom nightlyRatesPerRoom;
    @XmlElement(name = "Surcharges")
    private Surcharges surcharges;

    getters and setters go here

NightlyRatesPerRoom

@XmlRootElement(name = "NightlyRatesPerRoom")
@XmlAccessorType(XmlAccessType.FIELD)
public class NightlyRatesPerRoom {
    @XmlAttribute(name = "size")
    private int size;
    @XmlElement(name = "NightlyRate")
    private List<NightlyRate> nightlyRates;

    getters and setters go here

每晚汇率

@XmlRootElement(name = "NightlyRate")
@XmlAccessorType(XmlAccessType.FIELD)
public class NightlyRate {
    @XmlAttribute(name = "baseRate")
    private double baseRate;
    @XmlAttribute(name = "rate")
    private double rate;
    @XmlAttribute(name = "promo")
    private boolean promo;

    getters and setters go here

附加费

@XmlRootElement(name = "Surcharges")
@XmlAccessorType(XmlAccessType.FIELD)
public class Surcharges {
    @XmlAttribute(name = "size")
    private int size;
    @XmlElement(name = "Surcharge")
    private List<Surcharge> surcharges;

    getters and setters go here

附加费

@XmlRootElement(name = "Surcharge")
@XmlAccessorType(XmlAccessType.FIELD)
public class Surcharge {
    @XmlAttribute(name = "type")
    private String type;
    @XmlAttribute(name = "amount")
    private double amount;

    getters and setters go here

增值

@XmlRootElement(name = "ValueAdds")
@XmlAccessorType(XmlAccessType.FIELD)
public class ValueAdds {
    @XmlElement(name = "size")
    private int size;
    @XmlElement(name = "ValueAdd")
    private ValueAdd valueAdd;

    getters and setters go here

加值

@XmlRootElement(name = "ValueAdd")
@XmlAccessorType(XmlAccessType.FIELD)
public class ValueAdd {
    @XmlElement(name = "description")
    private String description;

    getters and setters go here

你的schema声明elementFormDefault="qualified" 正如我们在你的package-info中看到的,所以你必须移除根元素的ns2前缀,或者你必须将它添加到所有的内部元素,取决于xmlns 声明(我们看不到)。