0

I am trying to send a REST request, the first part of response is available but I cannot access the second part.

<SearchResults>
<TotalHotelsFound>7250</TotalHotelsFound>
<CheckInDate>2016-01-07</CheckInDate>
<CheckOutDate>2016-01-09</CheckOutDate>
<Currency>EUR</Currency>
<SearchId>HB-82365485</SearchId>
<Hotels>
  <Hotel>
    <HotelCode>FRYX72</HotelCode>
    <ProcessId>O3-69817815</ProcessId>
    <BoardType>Room Only</BoardType>
    <BookingURL>http://www.otel.com/hotels/nomad_paris_roissy_cdg_hotel.htm?processid=HB-82326485FRYX734</BookingURL>
    <TotalPrice>87</TotalPrice>
    <FreeCancel>unknown</FreeCancel>   
    <PaymentType>prepaid</PaymentType>
    <Tax>14</Tax>
    <AverageNightRate>43</AverageNightRate>
    <RoomTypes>Double Or Twin/Double Standard</RoomTypes>
    <AverageRatePerNightPerRoom>43.36</AverageRatePerNightPerRoom>
    <Rooms>
     <Room>
       <Type>double or twin standard</Type>
       <RoomDesc>Double Or Twin Standard</RoomDesc>
       <Adults>2</Adults>
       <Children/>
       <TotalRate>87</TotalRate>
       <Tax>12</Tax>
       <Rates/>
       <AverageNightRoomRate>43</AverageNightRoomRate>
    </Room>
   </Rooms>
  </Hotel>
  <Hotel>
    <HotelCode>FRYX72</HotelCode>
    <ProcessId>O0-63816095</ProcessId>
    <BoardType>Room Only</BoardType>
    <BookingURL>http://www.otel.com/hotels/nomad_paris_roissy_cdg_hotel.htm?processid=HB-82356285FRYX789</BookingURL>  
    <TotalPrice>87</TotalPrice>
    <FreeCancel>unknown</FreeCancel>
    <PaymentType>prepaid</PaymentType>
    <Tax>14</Tax>
    <AverageNightRate>43</AverageNightRate>
    <RoomTypes>Double Or Twin/Double Standard</RoomTypes>
    <AverageRatePerNightPerRoom>43.36</AverageRatePerNightPerRoom>
    <Rooms>
      <Room>
        <Type>double or twin standard</Type>
        <RoomDesc>Double Or Twin Standard</RoomDesc>
        <Adults>2</Adults>
        <Children/>
        <TotalRate>87</TotalRate>
        <Tax>12</Tax>
        <Rates/>
        <AverageNightRoomRate>43</AverageNightRoomRate>
      </Room>
   </Rooms>
</Hotel>

Code

try {
            System.err.println(">>> Otel");
            final String AFFILIATE = "Username";
            final String URL = "http://ws.hotelspro.com/xml/test-search-otel.php?affiliate="
                    + AFFILIATE;
            String readyUrl = URL + "&country=FR&city=Paris&checkin=2016-1-7&checkout=2016-1-9&currency=EUR&rooms=1&adults1=2";
            System.err.println(">>>" + readyUrl);
            RestTemplate restTemplate = new RestTemplate();
            SearchResults searchResults = restTemplate.getForObject(readyUrl,
                    SearchResults.class);
            if (searchResults == null) {
                System.err.println("it is null");
            } else {
                System.err.println("message:>>"
                        + searchResults.getTotalHotelsFound());
            }
            System.err.println(">>>" + searchResults.getHotels().size());
            System.err.println(">>>" + searchResults.getHotels().get(0).getHotelCode());
            System.err.println(">>>" + searchResults.getHotels().get(0).getHotelCode());
            System.err
                    .println("Otel>>>" + searchResults.getHotels().get(0).getPaymentType());
            System.err.println("event>>" + searchResults.getHotels().get(0).getBookingUrl());
        } catch (NullPointerException e) {
            e.printStackTrace();
        }   

JAXB

@XmlRootElement(name = "SearchResults")
@XmlAccessorType(XmlAccessType.FIELD)
public class SearchResults {
    @XmlElement(name = "TotalHotelsFound")
    private int totalHotelsFound;
    @XmlElement(name = "CheckInDate")
    private Date checkInDate;
    @XmlElement(name = "CheckOutDate")
    private Date checkOutDate;
    @XmlElement(name = "Currency")
    private String currency;
    @XmlElement(name = "SearchId")
    private String searchId;
    @XmlElement(name = "Hotels")
    private List<Hotel> hotels;
     getters and setters


@XmlRootElement(name = "Hotel")
@XmlAccessorType(XmlAccessType.FIELD)
public class Hotel {
    @XmlElement(name = "HotelCode")
    private String hotelCode;
    @XmlElement(name = "ProcessId")
    private String processId;
    @XmlElement(name = "BoardType")
    private String boardType;
    @XmlElement(name = "BookingURL")
    private String bookingUrl;
    @XmlElement(name = "TotalPrice")
    private double totalPrice;
    @XmlElement(name = "FreeCancel")
    private String freeCancel;
    @XmlElement(name = "PaymentType")
    private String paymentType;
    @XmlElement(name = "Tax")
    private int tax;
    @XmlElement(name = "AverageNightRate")
    private double averageNightRate;
    @XmlElement(name = "RoomTypes")
    private String roomType;
    @XmlElement(name = "AverageRatePerNightPerRoom")
    private double averageRatePerNightPerRoom;
    @XmlElement(name = "Rooms")
    private List<Room> rooms;
    getters and setters


@XmlRootElement(name = "Room")
@XmlAccessorType(XmlAccessType.FIELD)
public class Room {
    @XmlElement(name = "Type")
    private String type;
    @XmlElement(name = "RoomDesc")
    private String roomDesc;
    @XmlElement(name = "Adults")
    private int adults;
    @XmlElement(name = "Children")
    private int children;
    @XmlElement(name = "TotalRate")
    private double totalRate;
    @XmlElement(name = "Tax")
    private double tax;
    @XmlElement(name = "Rates")
    private String rates;
    @XmlElement(name = "AverageNightRoomRate")
    private int averageNightRoomRate;
    getters and setters

Output

I am receiving following output, as shown below first section is read but Hotels list wont get populated.

message:>>7258
>>>1
>>>null
>>>null
Otel>>>null
event>>null
Jack
  • 6,430
  • 27
  • 80
  • 151
  • You have set Content-type properly to fetch remaining data. Have a look at http://stackoverflow.com/questions/13038529/force-spring-resttemplate-to-use-xmlconverter if it is helpful for you – Ravindra babu Oct 17 '15 at 07:24
  • Can you try to add @XmlAttribute(name="hotel") over the getter method of hotels, like @XmlAttribute(name="hotel") – Burak Keceli Oct 17 '15 at 07:59
  • @BurakKeceli it returns message:>>7066 java.lang.NullPointerException at com.otel.App.main(App.java:32) – Jack Oct 17 '15 at 08:09

2 Answers2

1

Your need to use @XmlElementWrapper for Lists

@XmlRootElement(name = "SearchResults")
@XmlAccessorType(XmlAccessType.FIELD)
public static class SearchResults {
    @XmlElement(name = "TotalHotelsFound")
    private int totalHotelsFound;
    @XmlElement(name = "CheckInDate")
    private Date checkInDate;
    @XmlElement(name = "CheckOutDate")
    private Date checkOutDate;
    @XmlElement(name = "Currency")
    private String currency;
    @XmlElement(name = "SearchId")
    private String searchId;
    @XmlElementWrapper(name = "Hotels")
    @XmlElement(name = "Hotel")
    private List<Hotel> hotels;

}

and the same for the room

Anatoly Deyneka
  • 1,238
  • 8
  • 13
  • I feel it may be important to point out that this answer could be a little misleading. You don't explicitly **need** @XmlElementWrapper for all lists as a generalization. It does make sense in this case however, because the hotels element doesn't contain any other element – kirsty Oct 19 '15 at 13:32
  • @XmlElementWrapper is efficient way of working with collections in jaxb. – Anatoly Deyneka Oct 19 '15 at 14:09
  • It works thanks I will double check it and get back to you. – Jack Oct 20 '15 at 20:33
0

I believe you may have a couple of missing tags in your example XML, specificaaly </Hotels> and </SearchResults>

Your code above suggests that you have tried to specify multiple root elements. First of all, this is incorrect. SearchResults will be your root element, and all other elements are contained. This is more accurate JAXB code:

SearchResults class:

@XmlRootElement(name = "SearchResults")
@XmlAccessorType(XmlAccessType.FIELD)
public class SearchResults {
    @XmlElement(name = "TotalHotelsFound")
    private int totalHotelsFound;
    @XmlElement(name = "CheckInDate")
    private Date checkInDate;
    @XmlElement(name = "CheckOutDate")
    private Date checkOutDate;
    @XmlElement(name = "Currency")
    private String currency;
    @XmlElement(name = "SearchId")
    private String searchId;
    @XmlElement(name = "Hotels")
    private Hotels hotels;

    //getters and setters
}

Hotels class:

@XmlAccessorType(XmlAccessType.FIELD)
public class Hotels {
    @XmlElement(name = "Hotel")
    private List<Hotel> hotel;

    //getters and setters
}

Hotel class:

@XmlAccessorType(XmlAccessType.FIELD)
public class Hotel {
    @XmlElement(name = "HotelCode")
    private String hotelCode;
    @XmlElement(name = "ProcessId")
    private String processId;
    ...etc

    //getters and setters
}

I hope this helps.

kirsty
  • 267
  • 1
  • 2
  • 14
  • I removed those XMLRootElement annotations and it returns NullPointerException on this line System.err.println(">>>" + searchResults.getHotels().size()); – Jack Oct 20 '15 at 20:28
  • So when you unmarshal your XML to the SearchResults object, are you validating it with a schema? It may also be worth making an instance of the Hotels object to use in your print statement for the avoidance of doubt that anything is wrong with the SearchResults object as a whole. – kirsty Oct 21 '15 at 09:23