When I send a request to web service the following response will be received. I am using the following code to unmarshall the response XML to an object, but it seems nothing will be put into the object.
Server's response
<?xml version="1.0" encoding="utf-8"?>
<AvailabilityResponse DateTime="2014-02-18 08:32:04" DurationSecs="1.32" xmlns="example.com">
<Success></Success>
<Results ResultCount="9">
<Result>
<Outbound>
<FlightSegment>
<Departure>
<Airport CodeContext="IATA">DUS</Airport>
<DateTime>2014-12-10T09:55:00</DateTime>
</Departure>
<Arrival>
<Airport CodeContext="IATA">ZRH</Airport>
<DateTime>2014-12-10T11:10:00</DateTime>
</Arrival>
<FlightNumber CodeContext="IATA">LX1017</FlightNumber>
</FlightSegment>
</Outbound>
<Inbound>
<FlightSegment>
<Departure>
<Airport CodeContext="IATA">ZRH</Airport>
<DateTime>2014-12-15T07:25:00</DateTime>
</Departure>
<Arrival>
<Airport CodeContext="IATA">DUS</Airport>
<DateTime>2014-12-15T08:50:00</DateTime>
</Arrival>
<FlightNumber CodeContext="IATA">LX1016</FlightNumber>
</FlightSegment>
</Inbound>
<FareInfos CurrencyCode="EUR">
<FareReference>Y,Y</FareReference>
<BaseAmount>30</BaseAmount>
<TaxAmount>58</TaxAmount>
<TotalFare>126</TotalFare>
</FareInfos>
<Url>http://myexample.com</Url>
</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
<Result>....</Result>
</Results>
</AvailabilityResponse>
Code
String queryString = "http://example.com";
try {
URL page = new URL(queryString);
HttpURLConnection conn = (HttpURLConnection) page.openConnection();
conn.connect();
System.err.println("Results ");
this.results = (AvailabilityResponse) JAXB.unmarshal(conn.getInputStream(),
AvailabilityResponse.class);
System.err.println("Output:" + this.results.getResults().getResult().size());
Result in console (as there are 9 results in the Results tag, this number should be 9
Results
Output:0
AvailabilityResponse
#XmlRootElement(name = "AvailabilityResponse")
#XmlAccessorType(XmlAccessType.FIELD)
public class AvailabilityResponse {
#XmlElement(name = "Results")
private Results results = null;
#XmlElement (name = "Success")
private String success;
public AvailabilityResponse() {
this.results = new Results();
}
getters & setters go here
}
Results
#XmlRootElement(name = "Results")
#XmlAccessorType(XmlAccessType.FIELD)
public class Results {
#XmlElement(name = "Result")
private List<Result> result = null;
public Results() {
this.result = new ArrayList();
}
getters & setters go here
}
Result
#XmlRootElement(name = "Result")
#XmlAccessorType(XmlAccessType.FIELD)
public class Result {
#XmlElement(name = "Outbound")
private Outbound outbound = null;
#XmlElement(name = "Inbound")
private Inbound inbound = null;
#XmlElement(name = "FareInfos")
private FareInfos fareInfos = null;
#XmlElement (name = "Url")
private String Url;
public Result() {
this.outbound = new Outbound();
this.inbound = new Inbound();
this.fareInfos = new FareInfos();
}
getters & setters go here
}
OutBound
#XmlRootElement(name = "Outbound")
#XmlAccessorType(XmlAccessType.FIELD)
public class Outbound {
#XmlElement(name = "FlightSegment")
private FlightSegment flightSegment = null;
public Outbound() {
this.flightSegment = new FlightSegment();
}
getter & setter go here
}
InBound
#XmlRootElement(name = "Inbound")
#XmlAccessorType(XmlAccessType.FIELD)
public class Inbound {
#XmlElement(name = "FlightSegment")
private FlightSegment flightSegment = null;
public Inbound() {
this.flightSegment = new FlightSegment();
}
getter & setter go here
}
FlightSegment
#XmlRootElement(name = "FlightSegment")
#XmlAccessorType(XmlAccessType.FIELD)
public class FlightSegment {
#XmlElement(name = "Departure")
private Departure departure = null;
#XmlElement(name = "Arrival")
private Arrival arrival = null;
#XmlElement(name = "FlightNumber")
private String flightNumber;
public FlightSegment() {
this.departure = new Departure();
this.arrival = new Arrival();
}
getters & setters go here
}
Departure
#XmlRootElement (name = "Departure")
#XmlAccessorType (XmlAccessType.FIELD)
public class Departure {
#XmlElement (name = "Airport")
private String Airport;
#XmlElement (name = "DateTime")
private String DateTime;
getters & setters go here
}
Arrival
#XmlRootElement(name = "Arrival")
#XmlAccessorType(XmlAccessType.FIELD)
public class Arrival {
#XmlElement(name = "Airport")
private String Airport;
#XmlElement(name = "DateTime")
private String DateTime;
getters & setters go here
}
FareInfos
#XmlRootElement (name = "FareInfos")
#XmlAccessorType(XmlAccessType.FIELD)
public class FareInfos {
#XmlElement (name = "FareReference")
private String fareReference;
#XmlElement (name = "BaseAmount")
private String baseAmount;
#XmlElement (name ="TaxAmount")
private String taxAmount;
#XmlElement (name = "TotalFare" )
private String totalFare;
getters & setters go here
}
Since your XML document is namespace qualified you will need to use the package level #XmlSchema annotation to map the namespace qualification.
#XmlSchema(
namespace = "example.com",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Related
I'm trying to integrate with some provider REST API within xml. I have two requests and two very similar responses: Operation response and Check response.
Operation:
<Response>
<ReturnCode>0</ReturnCode>
<ReturnMessage>OK</ReturnMessage>
<Commands>
<OperationResponseCommand>
<ResultCode>412</ResultCode>
<ResultMessage>Some message hear</ResultMessage>
<OperationId>125206188472552900</OperationId>
<Id>14507921</Id>
</OperationResponseCommand>
</Commands>
</Response>
Check:
<Response>
<ReturnCode>0</ReturnCode>
<ReturnMessage>OK</ReturnMessage>
<Commands>
<CheckResponseCommand>
<ResultCode>412</ResultCode>
<ResultMessage>Some message hear</ResultMessage>
<OperationId>125206188472552900</OperationId>
</CheckResponseCommand>
</Commands>
</Response>
As you can see, the differences are:
<OperationResponseCommand> instead of <CheckResponseCommand>
in first xml.
One additional tag <Id> inside
<OperationResponseCommand>.
And I have two classes for Response and for Command.
First:
#Data
#XmlRootElement(name = "Response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
#XmlElement(name = "ReturnCode")
private Integer returnCode;
#XmlElement(name = "ReturnMessage")
private String returnMessage;
#XmlElementWrapper(name = "Commands")
#XmlElement(name = "OperationResponseCommand")
private List<Command> commands = new ArrayList<>();
}
Second:
#Data
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Command {
#XmlElement(name = "ResultCode")
private Integer resultCode;
#XmlElement(name = "ResultMessage")
private String resultMessage;
#XmlElement(name = "OperationId")
private String operationId;
#XmlElement(name = "Id")
private Integer id;
}
For building response object from xml I'm using this class:
public class JAXBOperations {
public <T> T buildObjectFromXml(Class<T> clazz, String xml) {
try {
StringReader reader = new StringReader(xml);
Unmarshaller unmarshaller = createUnmarshaller(clazz);
return (T) unmarshaller.unmarshal(reader);
} catch (JAXBException e) {
throw new RuntimeException("Exception has been occurred while creating unmarshaller to parse xml to object");
}
}
public <T> String buildXmlFromObject(T objectToXml) {
try {
StringWriter writer = new StringWriter();
Marshaller marshaller = createMarshaller(objectToXml.getClass());
marshaller.marshal(objectToXml, writer);
return writer.toString();
} catch (JAXBException e) {
throw new RuntimeException("Exception has been occurred while creating marshaller to parse object to xml");
}
}
private <T> Marshaller createMarshaller(Class<T> clazz) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
return jaxbContext.createMarshaller();
}
private <T> Unmarshaller createUnmarshaller(Class<T> clazz) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
return jaxbContext.createUnmarshaller();
}
}
Method buildObjectFromXml. And it works fine for first xml response. I have an object like this:
Response(
returnCode=0, returnMessage=OK,
commands=[Command(
resultCode=417,
resultMessage=Processing,
operationId=b6619f26-8583-4272-b89d-d1b200109d06,
id=157427079)])
But for the second xml response it doesn't works. I have:
Response(
returnCode=0,
returnMessage=OK,
commands=[])
I tried to change the code of my Response class. Like this:
#Data
#XmlRootElement(name = "Response")
#XmlAccessorType(XmlAccessType.FIELD)
public class tResponse {
#XmlElement(name = "ReturnCode")
private Integer returnCode;
#XmlElement(name = "ReturnMessage")
private String returnMessage;
#XmlElementWrapper(name = "Commands")
#XmlElementRefs({
#XmlElementRef(name = "OperationResponseCommand", type = Command.class),
#XmlElementRef(name = "CheckResponseCommand", type = Command.class)})
private List<Command> commands = new ArrayList<>();
}
Or this:
#Data
#XmlRootElement(name = "Response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
#XmlElement(name = "ReturnCode")
private Integer returnCode;
#XmlElement(name = "ReturnMessage")
private String returnMessage;
#XmlElementWrapper(name = "Commands")
#XmlElement(name = "OperationResponseCommand")
private List<Command> operstionCommands = new ArrayList<>();
#XmlElementWrapper(name = "Commands")
#XmlElement(name = "CheckResponseCommand")
private List<Command> checkCommands = new ArrayList<>()
}
But it both doesn't works too.
My question is: what I'm doing wrong? How can I change code of my two classes to correct converting to object both types of xml responses?
For representing the XML elements <OperationResponseCommand>
and <CheckResponseCommand> you will need separate classes
which should be subclasses of your Command classes.
Let's call them OperationResponseCommand and CheckResponseCommand.
The properties common to all commands should remain in your
Command class. It is also a good idea to declare this class as abstract.
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class Command {
#XmlElement(name = "ResultCode")
private Integer resultCode;
#XmlElement(name = "ResultMessage")
private String resultMessage;
#XmlElement(name = "OperationId")
private Integer operationId;
}
The properties specific for the commands should go into the subclasses:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class OperationResponseCommand extends Command {
#XmlElement(name = "Id")
private Integer id;
}
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class CheckResponseCommand extends Command {
}
Finally, in your Response class you need to enhance the annotations
of your List<Command> commands property, so that JAXB
will know which object class needs to be instantiated depending
on the XML element name of the commands.
(See also the javadoc of #XmlElements.)
#XmlElementWrapper(name = "Commands")
#XmlElements({
#XmlElement(name = "OperationResponseCommand", type = OperationResponseCommand.class),
#XmlElement(name = "CheckResponseCommand", type = CheckResponseCommand.class)
})
private List<Command> commands = new ArrayList<>();
I'm stuck. How to parse Node with same name child node?
In this example i need nodes with rate attribute.
<xml>
<Rates>
<Rates winrate_cap="9999">
<Rates rate="323"/>
<Rates rate="343"/>
<Rates rate="2338"/>
<Rates rate="233"/>
</Rates>
</Rates>
</xml>
My response wrapper class:
#Root(name = "xml", strict = false)
public class XMLResponse {
#ElementList(entry = "Rates")
public List<Rates> response;
public static class Rates {
#Attribute(name = "winrate_cap", required = false)
public String winrate_cup;
#ElementList(required = false, entry = "Rates")
public List<Rates> rates;
}
public static class Rates {
#Attribute(name = "rate", required = false)
public String rate;
}
}
You are on the right way. As you have many Rates here, better name the class more with more context and set the xml name via Annotation.
I've separated the XMLResponse and Rates classes, but this doesn't make any difference.
The class XMLRespone maps the <xml>...</xml> part:
#Root(name = "xml")
public class XMLRespone
{
#Element(name = "Rates")
private Rates rates;
// ...
}
All types for <Rates...>...</Rates> is done by Rates class (and it's inner classes, which map the structure:
#Root(name = "Rates")
public class Rates
{
#Element(name = "Rates")
private RateList rates;
// ...
public static class RateList
{
#ElementList(entry = "Rates", inline = true)
private ArrayList<RateValue> values;
#Attribute(name = "winrate_cap", required = true)
private int winrateCap;
// ...
}
public static class RateValue
{
#Attribute(name = "rate", required = true)
private int rate;
// ...
}
}
Deserializing your XML gives this output (using generated toString()):
XMLRespone{rates=Rates{rates=RateList{values=[RateValue{rate=323}, RateValue{rate=343}, RateValue{rate=2338}, RateValue{rate=233}], winrateCap=9999}}}
I am trying to send a REST request and parse the response, but it returns NullPointerException. I assume the issue is with namespace.
When I have package-info.java file, it returns NullPointerException and when I do not it returns following:
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>
If I remove qualified part of package-info the code shows following:
>>>0ABD9-732-A12-124-2BE4FD21A
>>>1
nullPointerException
....
Sample partial response
<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><p><b>Property Location</b>
<br />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¤cy=USD&standardCheckin=11/23/2016&standardCheckout=11/25/2016&roomsCount=1&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">
Request
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());
package-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
HotelList
#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
HotelSummary
#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
RoomRateDetails
#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
RateInfo
#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
NightlyRate
#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
Surcharges
#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
Surcharge
#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
ValueAdds
#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
ValueAdd
#XmlRootElement(name = "ValueAdd")
#XmlAccessorType(XmlAccessType.FIELD)
public class ValueAdd {
#XmlElement(name = "description")
private String description;
getters and setters go here
Your schema declares elementFormDefault="qualified" as we can see in your package-info, so you must remove the ns2 prefix at the root Element, or you must add it to all the inner elements, depends on the xmlns declaration (that we can't see).
I'm using Simple framework to deserialize an xml on my android app .
The issue is on a portion of the xml because I can get the objects of the other portions of it .
Here is the part of the xml that I struggle with :
<webtv name="channelname" date="2014-10-31">
<config>
<pathVideo extension="mp4">http://vodflash.channelname.com/tv_conn/1/country/</pathVideo>
<pathBigImage extension="jpg">http://vodflash.channelname.com/tv_conn/1/country/pic/320x180/</pathBigImage>
<pathImage extension="jpg">http://vodflash.channelname.com/tv_conn/1/country/pic/160x90/</pathImage>
<pays>GB;IE</pays>
</config>
Here is my XmlMapper class :
#Root(name="webtv", strict = false)
public class XmlModelMapper {
public ConfigObject getConfigObjects() {
return configObject;
}
#Element(name="config")
public ConfigObject configObject = new ConfigObject();
#ElementList(name = "itemList")
private List<Videos> itemList = new ArrayList<Videos>();
public List<Videos> getItemList() {
return itemList;
}
#ElementList(name = "chaineList")
private List<Chaine> chaineList = new ArrayList<Chaine>();
public List<Chaine> getChaineList() {
return chaineList;
}
}
If I change my mapper class to this :
#Root(name="webtv", strict = false)
public class XmlModelMapper {
public List<ConfigObject> getConfigObjects() {
return configObject;
}
//change is here using a list not an object
#ElementList(name="config")
public List<ConfigObject> configObjects = new ArrayList<ConfigObject>();
#ElementList(name = "itemList")
private List<Videos> itemList = new ArrayList<Videos>();
public List<Videos> getItemList() {
return itemList;
}
#ElementList(name = "chaineList")
private List<Chaine> chaineList = new ArrayList<Chaine>();
public List<Chaine> getChaineList() {
return chaineList;
}
}
and the log the size of the List I get 4 which is correct , but how to get each object in a distinct way including the extension (attribute)
Please help me solving this issue .
Thanks
#ElementList(name="config")
public List<ConfigObject> configObjects = new ArrayList<ConfigObject>();
This wont match with your xml listed above. While the #Element-based solution (example 1) will create a proper config-tag, the list adds another "list-tag"; here's an example:
<config> <!-- This is the list's tag, wrapping all elements -->
<config> <!-- This is the actual element's tag -->
<pathVideo extension="mp4">http://video.com</pathVideo>
<pathBigImage extension="jpg">http://bigimg.com</pathBigImage>
<pathImage extension="jpg">http://image.com</pathImage>
<pays>GB;IE</pays>
</config>
<!-- some more <config>...</config> -->
</config>
The solution: Use athe inline list - those don't have the "list-tag".
#ElementList(name = "config", inline = true, entry = "config")
public List<ConfigObject> configObjects = new ArrayList<>();
For the sake of completeness, here are my classes used for testing:
class Chaine { /* empty - enough for testing */ }
class Videos { /* empty - enough for testing */ }
#Root
public class ConfigObject
{
#Element(name = "pathVideo")
private PathConfig video;
#Element(name = "pathBigImage")
private PathConfig bigImage;
#Element(name = "pathImage")
private PathConfig image;
#Element(name = "pays")
private String pays;
// ...
}
#Root
public class PathConfig
{
#Attribute(name = "extension")
private String extension;
#Text
private String path;
// ...
}
Solved my issue and learned alot about simple framework which is great and light weight , but I prefer ollo's answer
Please discard ormlite annotations
My classes :
#Root(name="webtv", strict = false)
public class XmlModelMapper {
public ConfigObject getConfigObject() {
return configObject;
}
#Element(name="config")
public ConfigObject configObject = new ConfigObject();
//rest of the elements
...
}
and
#Root(name = "config" , strict = false)
public class ConfigObject {
#Element
PathVideo pathVideo;
#Element
PathImage pathImage;
#Element
PathBigImage pathBigImage ;
//rest of the elements
}
and
#Root(name = "pathImage")
#DatabaseTable(tableName = "imageconfig")
public class PathImage {
#DatabaseField(generatedId = true)
Integer id ;
#Attribute
#DatabaseField
String extension;
#Text
#DatabaseField
String pathImage;
//rest of the elements...
}
and
#Root(name = "pathVideo")
#DatabaseTable(tableName = "videoconfig")
public class PathVideo {
#DatabaseField(generatedId = true)
Integer id ;
#Attribute
#DatabaseField
String extension;
#Text
#DatabaseField
String pathVideo;
}
and finally
#Root(name = "pathBigImage")
#DatabaseTable(tableName = "bigimageconfig")
public class PathBigImage {
#DatabaseField(generatedId = true)
Integer id ;
#Attribute
#DatabaseField
String extension;
#Text
#DatabaseField
String pathBigImage;
//rest of the elements...
}
I want to convert context of xml file to java object.
But some part is extracted ok, and some has null values.
Here is xml file:
<OTA_AirLowFareSearchRQ EchoToken="50987" SequenceNmbr="1" Target="Production" TimeStamp="2003-11-19T19:44:10-05:00"
Version="2.001"
xsi:schemaLocation="http://www.opentravel.org/OTA/2003/05 OTA_AirLowFareSearchRQ.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.opentravel.org/OTA/2003/05">
<POS>
<TPA_Extensions>
<TPA_Extension>
<PromoRatesRequired Value="false"/>
<UserName Value="342561"/>
<UserPassword Value="1234"/>
<ClearCache Value="true"/>
</TPA_Extension>
</TPA_Extensions>
</POS>
<OriginDestinationInformation>
<DepartureDateTime>2015-04-13T00:00:00</DepartureDateTime>
<OriginLocation LocationCode="DUB"/>
<DestinationLocation LocationCode="CDG"/>
</OriginDestinationInformation>
<TravelPreferences>
<CabinPref PreferLevel="Preferred" Cabin="Economy"/>
</TravelPreferences>
<TravelerInfoSummary>
<AirTravelerAvail>
<PassengerTypeQuantity Code="ADT" Quantity="1"/>
<PassengerTypeQuantity Code="CHD" Quantity="0"/>
<PassengerTypeQuantity Code="INF" Quantity="1"/>
</AirTravelerAvail>
</TravelerInfoSummary>
</OTA_AirLowFareSearchRQ>
I have trouble with extracting 'OriginDestinationInformation' and 'AirTravelerAvail'.
Here is main():
public static void main(String[] args) {
try {
JAXBContext context = JAXBContext.newInstance(OTAAirLowFareSearchRQ.class);
Unmarshaller um = context.createUnmarshaller();
OTAAirLowFareSearchRQ rq = (OTAAirLowFareSearchRQ) um.unmarshal(new FileReader(FILE_NAME));
System.out.println(rq);
} catch (FileNotFoundException | JAXBException e) {
LOGGER.error(e);
}
}
Here is output snippet:
originDestinationInformation=[OriginDestinationInformation{
departureDateTime=null,
originLocation=null,
destinationLocation=null,
alternateLocationInfo=null,
rph='null',
refNumber=null}],
travelerInfoSummary=TravelerInfoSummary{
ticketingCountryCode='null',
specificPTCIndicator=null,
airTravelerAvails=null},
echoToken='50987',
timeStamp=2003-11-19T19:44:10-05:00,
target='Production',
version=2.001,
transactionIdentifier='null',
sequenceNmbr=1,
And much more interesting part OriginDestinationInformation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "OriginDestinationInformation", propOrder = {
"departureDateTime",
"originLocation",
"destinationLocation",
"tpaExtensions",
"alternateLocationInfo",
"rph",
"refNumber"
})
public static class OriginDestinationInformation extends OriginDestinationInformationType {
#XmlElement(name = "DepartureDateTime", required = true)
protected TimeInstantType departureDateTime;
#XmlElement(name = "OriginLocation", required = true)
protected OriginLocation originLocation;
#XmlElement(name = "DestinationLocation", required = true)
protected DestinationLocation destinationLocation;
#Transient
#XmlElement(name = "AlternateLocationInfo")
protected AlternateLocationInfo alternateLocationInfo;
#XmlElement(name = "TPA_Extensions")
protected TPAExtensionsType tpaExtensions;
#XmlAttribute(name = "RPH")
protected String rph;
#XmlAttribute(name = "RefNumber")
protected Integer refNumber;
// getters and setters
TimeInstantType:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "TimeInstantType", propOrder = {
"value"
})
public class TimeInstantType {
#Property("dateTime")
#XmlValue
protected String value;
// rest of class
OriginLocation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "OriginLocation")
public static class OriginLocation extends LocationType {
#XmlAttribute(name = "MultiAirportCityInd")
protected Boolean multiAirportCityInd;
#XmlAttribute(name = "AlternateLocationInd")
protected Boolean alternateLocationInd;
#XmlAttribute(name = "LocationCode")
protected String locationCode;
DestinationLocation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "DestinationLocation")
public static class DestinationLocation extends LocationType {
#XmlAttribute(name = "MultiAirportCityInd")
protected Boolean multiAirportCityInd;
#XmlAttribute(name = "AlternateLocationInd")
protected Boolean alternateLocationInd;
#XmlAttribute(name = "LocationCode")
protected String locationCode;
and for list of objects TravelerInfoSummary
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "TravelerInfoSummary", propOrder = {
"airTravelerAvails",
"ticketingCountryCode",
"specificPTCIndicator"
})
public static class TravelerInfoSummary extends TravelerInfoSummaryType {
#Embedded
#XmlElement(name = "AirTravelerAvail")
protected List<AirTravelerAvail> airTravelerAvails;
AirTravelerAvail:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "AirTravelerAvail")
public class AirTravelerAvail {
#Embedded
#XmlElement(name = "PassengerTypeQuantity")
#XmlElementWrapper(name = "AirTravelerAvail")
protected List<PassengerTypeQuantity> passengerTypeQuantities;
I couldn't figure out what is wrong here. I tried
#XmlElementWrapper(name = "AirTravelerAvail")
for list of objects but it keep getting null.
How to solve this trouble?
To start off, I hate JAXB!
That said, i literally have to specify
#XmlElemnt(namespace = "namespace")
on every element of a class. JAXB simply does not assign the default namespace to the current xml dom.
By default, JAXB seems to work with ElementFormDefault="unqualified" and AttributeFormDefault="qualified" (I may have confused this), but this makes it unmarshall the root element, considering only attributes as belonging to the default-namespace.
If the namespace has a prefix e.g. xmlns:ns="namespace", then JAXB will correctly marshall elements as to belonging to this namespace.
If you have control over xml, simply have a prefix to the default namespace, like
xmlns:ns="http://www.opentravel.org/OTA/2003/05"
If you dont, make sure to have
#XmlElement(namespace = "http://www.opentravel.org/OTA/2003/05")
on every element that is not an attribute.
package com.anosym.stackoverflow.stackoverflow;
import java.util.Calendar;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import static com.anosym.stackoverflow.stackoverflow.Main.calendarString;
import static javax.xml.bind.annotation.XmlAccessType.FIELD;
#XmlRootElement(name = "OTA_AirLowFareSearchRQ", namespace = "http://www.opentravel.org/OTA/2003/05")
#XmlAccessorType(FIELD)
public class OTAAirLowFareSearchRQ {
#XmlAttribute(name = "EchoToken")
private String echoToken;
#XmlAttribute(name = "SequenceNmbr ")
private int sequenceNmbr;
#XmlAttribute(name = "Target")
private String target;
#XmlAttribute(name = "TimeStamp")
private Calendar timeStamp;
#XmlAttribute(name = "Version")
private String version;
#XmlElement(name = "POS", namespace = "http://www.opentravel.org/OTA/2003/05")
private POS pos;
#XmlElement(name = "OriginDestinationInformation", namespace = "http://www.opentravel.org/OTA/2003/05")
private OriginDestinationInformation destinationInformation;
public OTAAirLowFareSearchRQ(String echoToken, int sequenceNmbr, String target, Calendar timeStamp, String version,
POS pos, OriginDestinationInformation destinationInformation) {
this.echoToken = echoToken;
this.sequenceNmbr = sequenceNmbr;
this.target = target;
this.timeStamp = timeStamp;
this.version = version;
this.pos = pos;
this.destinationInformation = destinationInformation;
}
public OTAAirLowFareSearchRQ() {
}
#Override
public String toString() {
return "OTAAirLowFareSearchRQ{"
+ "echoToken=" + echoToken + ", "
+ "sequenceNmbr=" + sequenceNmbr + ", "
+ "target=" + target + ", "
+ "timeStamp=" + calendarString(timeStamp) + ", "
+ "version=" + version + ", "
+ "pos=" + pos + ", "
+ "destinationInformation=" + destinationInformation + '}';
}
}
package com.anosym.stackoverflow.stackoverflow;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import static javax.xml.bind.annotation.XmlAccessType.FIELD;
#XmlAccessorType(FIELD)
public class POS {
#XmlElement(name = "TPA_Extension", namespace = "http://www.opentravel.org/OTA/2003/05")
#XmlElementWrapper(name = "TPA_Extensions", namespace = "http://www.opentravel.org/OTA/2003/05")
private List<TPAExtension> tpaExtensions;
public POS(List<TPAExtension> tpaExtensions) {
this.tpaExtensions = tpaExtensions;
}
public POS() {
}
#Override
public String toString() {
return "POS{" + "tpaExtensions=" + tpaExtensions + '}';
}
}