I need to create a XML which matches this structure:
<OfferPackage Name="aaa">
<OfferPackage.Offers>
<OfferCollection Capacity="1">
<Offer Price="12.34"/>
<Offer Price="12.34"/>
</OfferCollection>
</OfferPackage.Offers>
</OfferPackage>
My problem is that I do not know how to achieve this here: <OfferPackage.Offers>. How I can get this "dot notation" with just annotations? All I got out looks like this:
<OfferPackage Name="aaa">
<OfferCollection Capacity="1">
<Offer Price="12.34"/>
<Offer Price="12.34"/>
</OfferCollection>
</OfferPackage>
This is my current code:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
#SneakyThrows
public String toString() {
var sw = new StringWriter();
var marshaller = JAXBContext
.newInstance(OfferPackage.class)
.createMarshaller();
marshaller.setProperty(JAXB_FRAGMENT, true);
marshaller.marshal(this, sw);
return sw.toString();
}
}
#XmlRootElement(name = "Offer")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferCollection {
#XmlAttribute(name = "Capacity")
private Integer capacity = null;
#XmlElement(name = "Offer")
private List<Offer> offer = null;
}
You can achieve the desired behavior using the #XmlElementWrapper annotation:
Generates a wrapper element around XML representation. This is primarily intended to be used to produce a wrapper XML element around collections.
In your case, it will look similar to this:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElementWrapper(name="OfferPackage.Offers")
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
#SneakyThrows
public String toString() {
var sw = new StringWriter();
var marshaller = JAXBContext
.newInstance(OfferPackage.class)
.createMarshaller();
marshaller.setProperty(JAXB_FRAGMENT, true);
marshaller.marshal(this, sw);
return sw.toString();
}
}
Other possibility will be to define an intermediate class, OfferPackageOffers to wrap the OfferCollection List::
#XmlRootElement(name = "OfferPackage.Offers")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackageOffers {
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
//...
}
And use the new class in OfferPackage instead of the mentioned OfferCollection List:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElement( name = "OfferPackage.Offers")
private OfferPackageOffers offers = null;
//...
}
Related
I have the following JAXB entity:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNER)
public class FilePartner
{
#XmlAttribute(name = EntityConstants.IDENTIFIER, required = true)
private String identifier;
#XmlElement(name = EntityConstants.NAME)
private String name;
#XmlElement(name = EntityConstants.ROOT_PATH)
private String rootPath;
...
}
which serialized into a similar structure:
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
I also have an entity which represents a list of partners:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private List<FilePartner> partners = new ArrayList<FilePartner>();
public List<FilePartner> getPartners()
{
return partners;
}
public void addPartners(List<FilePartner> partners)
{
this.partners.addAll(partners);
}
}
which serializes into:
<partners>
<file-partner identifier="foo">
...
</file-partner>
<file-partner identifier="foo2">
...
</file-partner>
...
</partners>
I am looking for a way to force the jaxb unmarshaller to deserialize XMLs in the form of
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
into FilePartnerList instances with list size of 1, i.e:
JAXBContext context = JAXBContext.newInstance(FilePartner.class, FilePartnerList.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
InputStream inputStream = getResourceAsStream(filePartnerAsXml);
FilePartnerList partnerList = (FilePartnerList) unmarshaller.unmarshal(inputStream); // This SHOULD be unmarshalled to FilePartnerList instead of FilePartner
assertTrue(partnerList.getPartners().getSize().equals(1));
How do I achieve that?
private List<FilePartner> partners = new ArrayList<FilePartner>(**1**);
That way you'll get a fixed size input array....
But I'm sure that you will want to get the XSD of that model with the 'maxocurrs=1' so you will end modifying the XSD manually.
Anyway: why don't you, if the list size must be fixed to '1', simply set it as a simple node with a single child? Something like this (untested):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private FilePartner partners;
public FilePartner getFilePartner()
{
return partner;
}
public void setPartner(FilePartner partner)
{
this.partner = partner;
}
}
This way you will have one and only one partner per parnets-list.
The XML that fullfits the XSD of your service a text and in that text is indistinguible a list with max size 1 and a node.
I'm getting null value when unmarshelling the xml file to java class. But the xml file as values corresponding to the its attributes. Is there any mistake in my pojo class or unmarshelling?
Please help
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "CardUpdateResponse",namespace="http://www.samople.com/Prepaid")
public class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
//Setters and Getters
}
This is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<CardUpdateResponse xmlns="http://www.samople.com/Prepaid">
<CARDUPDATE_RET>
<ResErrorMsg>ID Issue Date must be equal or less than present date</ResErrorMsg>
<ResErrorCode>ErrIsud01</ResErrorCode>
<ResCode>0</ResCode>
<ACCOUNTNUMBER>2000000003918246</ACCOUNTNUMBER>
</CARDUPDATE_RET>
</CardUpdateResponse>
this is code for unmarshelling
public class XmlUnmarshelling {
public void unmarshell()
{
try
{
System.out.println("xml unmarshelling class");
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(FVCardUpdateResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
FVCardUpdateResponse CARDUPDATE_ret = (FVCardUpdateResponse) jaxbUnmarshaller.unmarshal(file);
System.out.println("xml unmarshelled = "+CARDUPDATE_ret.getResErrorMsg());//Getting null value as response.
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Your POJO doesn't have the same structure as your XML. CardUpdateResponse doesn't directly contain the properties in your POJO, it contains CARDUPDATE_RET element which contains the properties.
You could modify your POJO like this to match the XML:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "CardUpdateResponse", namespace="http://www.samople.com/Prepaid")
public static class CardUpdateResponseWrapper {
#XmlElement(name="CARDUPDATE_RET")
private FVCardUpdateResponse response;
// Getter and setter for response
public static class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
// Getters and setters
}
}
Now the CardUpdateResponseWrapper class will represent your root XML element and it will have instance of FVCardUpdateResponse which will represent the CARDUPDATE_RET XML element.
Do unmarshall it, just call:
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(CardUpdateResponseWrapper.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
CardUpdateResponseWrapper wrapper = (CardUpdateResponseWrapper) jaxbUnmarshaller.unmarshal(file);
System.out.println(wrapper.getResponse().getResErrorMsg());
I think that the issue is a combination of two problems, one what Bohuslav is saying, the other you need to repeat your namespace on every XmlElement annotation, e.g.
#XmlElement(name = "ResCode", namespace="http://www.samople.com/Prepaid")
and one particular issue, you need to match the cases as well so the name for AccountNumber should be capitalized ACCOUNTNUMBER
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><p><b>Property Location</b> <br />With a stay at Rydges World Square, you'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&cid=55505&hotelID=150241&mode=2&numberOfRooms=1&room-0-adult-total=2&room-0-child-total=0&arrivalMonth=5&arrivalDay=18&departureMonth=5&departureDay=19&showInfo=true&locale=en_US&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)
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>
i need your help : please, please please.
I've a Xades-signed XML document that i receive as a byteArray : so i convert my byteArray to a String.
After, i try to unmarhall so that i obtain a Java Object mapped.
The result is that i get an instance of "MyJavaObj" with all informations but Xades-Signature. My signature is null in the Java Object while all other informations are well-mapped. The following is my java method. Please, help me to get the object signature in the instance of MyJavaObj.
<school>
<documentVersion>2.10</documentVersion>
<teacher>
.....
</teacher>
<student>
<name></name>
<age></age>
....
</student>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-2b72d2f4-4794-4a8b-8cbf-4c74d33629a7">
<ds:SignedInfo>
........
</ds:SignedInfo>
.......
</ds:Signature>
</school>
this is the method to convert
public static MyJavaObj unmarshallBinary(final byte[] pByteStr) {
try {
final String xmlFlow = new String(pByteStr, "UTF-8");
final StringBuffer xmlStr = new StringBuffer(xmlFlow);
// Unmarshalling with JAXB
final JAXBContext jaxbContext = JAXBContext.newInstance("generated.package");
// marshaller
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// Unmarshalling
final JAXBElement<MyJavaObj> root = unmarshaller.unmarshal(
new StreamSource(new StringReader(xmlStr.toString())), MyJavaObj.class);
return root.getValue();
} catch (final Throwable excep) {
excep.printStacktrace();
}
}
MyJavaObj result = unmarshallBinary(..a ByteArray..);
result.getDocumentVersion() : returns 2.10;
result.getStudent() : returns the students;
result.getSignature() : return NULL;
The file MyJavaObj.java is well annotated
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "My_Java_Obj", namespace = "urn:my_java_obj",
propOrder = {"documentVersion", "teacher", "student","signature"})
public class MyJavaObj {
#XmlElement(name = "documentVersion", required = true)
protected String documentVersion;
#XmlElement(name = "teacher", required = true)
protected Teacher teacher;
#XmlElement(name = "student", required = true)
protected Student student;
#XmlElement(name = "Signature")
protected Signature signature;
#XmlAttribute(name = "Id", required = true)
#XmlJavaTypeAdapter(CollapsedStringAdapter.class)
#XmlID
#XmlSchemaType(name = "ID")
protected String id;
.....
getters and setters
}
Thanks for any help.
The Signature element is in the http://www.w3.org/2000/09/xmldsig#" namespace so you need to include this in the #XmlElement for the signature field.
#XmlElement(name="Signature", namespace="http://www.w3.org/2000/09/xmldsig#")
protected Signature signature;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
my solution is bit different
i used uddi-ws. Maven dependency is here:
<!-- https://mvnrepository.com/artifact/org.apache.juddi/uddi-ws -->
<dependency>
<groupId>org.apache.juddi</groupId>
<artifactId>uddi-ws</artifactId>
<version>3.3.2</version>
</dependency>
In class:
//in my case, import org.w3.x2000.x09.xmldsig.SignatureType isn't working
import org.w3._2000._09.xmldsig_.SignatureType;
//Signature declaration
private SignatureType Signature;
//namespace is important part, without namespace, it returns null
#XmlElement(name = "Signature", namespace = "http://www.w3.org/2000/09/xmldsig#")
public SignatureType getSignature() {
return Signature;
}
More info:
https://www.codesynthesis.com/pipermail/xsd-users/2006-December/000674.html
In the root.class from my xi-schema, the element item and ohter objects are part of an itemList:
#XmlElementRef(name = "item", namespace = "xi", type = JAXBElement.class, required = false)
//...
protected List<Object> itemList;
I've in the ObjectFactory.class from the main-schema some items as JAXBElements like this:
#XmlElementDecl(namespace = "de-schema", name = "detailedInformation", substitutionHeadNamespace = "xi", substitutionHeadName = "item")
public JAXBElement<numItemType> createDetailedInformation(numItemType num) {
return new JAXBElement<numItemType>(_detailedInformation_QNAME, numItemType.class, null, num);
}
So the numItemType has some attributes and value(num) for the JAXBElement.
NumItemType.class:
#XmlJavaTypeAdapter(numItemTypeAdapter.class)
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
But when JAXB unmarshal the XML document, it will has only elements, for example:
<detailedInformation>
<element1>1234</element1>
<element2>5678</element2>
<element3>bla</element3>
</detailedInformation>
When I marshal it, it should become (like the JAXB java code):
<detailedInformation element2="5678" element3="bla">1234</detailedInformation>
Therefore, I have written an numItemTypeAdapter.class with
NumItemTypeAdapter extends XmlAdapter
AdaptedNum.class:
public class AdaptedNum {
#XmlElement
private double element1;
#XmlElement
private String element2;
#XmlElement
private String element3;
/** Some getter/setter methods */
}
I thought, that would be help me http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html, but it is all a bit tricky :-/
It's a bit tricky to sort out exactly where your problem may be occurring. I'm assuming your original model was generated from an XML Schema, this should work as is without any modifications. I've attempted below to provide a scaled down version of your example which may help.
Root
package forum11343610;
import java.util.*;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElementRef(name = "item", namespace = "xi", type = JAXBElement.class, required = false)
protected List<Object> itemList = new ArrayList<Object>();
public List<Object> getItemList() {
return itemList;
}
public void setItemList(List<Object> itemList) {
this.itemList = itemList;
}
}
NumItemType
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
ObjectFactory
package forum11343610;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;
#XmlRegistry
public class ObjectFactory {
private static final QName _detailedInformation_QNAME = new QName("de-schema", "detailedInformation");
#XmlElementDecl(namespace = "xi", name = "item")
public JAXBElement<NumItemType> createItem(NumItemType num) {
return new JAXBElement<NumItemType>(_detailedInformation_QNAME, NumItemType.class, null, num);
}
#XmlElementDecl(namespace = "de-schema", name = "detailedInformation", substitutionHeadNamespace = "xi", substitutionHeadName = "item")
public JAXBElement<NumItemType> createDetailedInformation(NumItemType num) {
return new JAXBElement<NumItemType>(_detailedInformation_QNAME, NumItemType.class, null, num);
}
}
Demo
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
ObjectFactory objectFactory = new ObjectFactory();
Root root = new Root();
NumItemType numItemType = new NumItemType();
numItemType.num = BigDecimal.TEN;
numItemType.decimals = "1";
numItemType.precision = "2";
root.getItemList().add(objectFactory.createDetailedInformation(numItemType));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:ns2="de-schema" xmlns:ns3="xi">
<ns2:detailedInformation precision="2" decimals="1">10</ns2:detailedInformation>
</root>
Thank your for your comment.
That's the point:
Demo
NumItemType numItemType = new NumItemType();
numItemType.num = BigDecimal.TEN;
numItemType.decimals = "1";
numItemType.precision = "2";
root.getItemList().add(objectFactory.createDetailedInformation(numItemType));
It should unmarshal and map the XML automatically.
XML Input
<detailedInformation>
<element1>1234</element1>
<element2>5678</element2>
<element3>bla</element3>
</detailedInformation>
With the Code:
Demo
JAXBContext jc = JAXBContext.newInstance(Root.class, ObjectFactory.class);
Unmarshaller u = jc.createUnmarshaller();
File xml = new File("D:/", "test.xml");
Root root = (Root) u.unmarshal(xml);
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:ns2="de-schema" xmlns:ns3="xi">
<ns2:detailedInformation precision="2" decimals="1">10</ns2:detailedInformation>
</root>
I could parse the XML Document with DOM to a tree and marhalling with JAXB...
Thank you!
In other words:
I want to set new elements to the NumItemType.class for the unmarshalling without change the schema java code.
NumItemType.class
package forum11343610;
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "numItemType", namespace = "xi", propOrder = {
"num"
})
#XmlJavaTypeAdapter(NumItemTypeAdapter.class)
public class NumItemType {
#XmlValue
protected BigDecimal num;
#XmlAttribute(name = "precision")
protected String precision;
#XmlAttribute(name = "decimals")
protected String decimals;
//... more Attributes
}
NumItemTypeAdapter.class
public class NumItemTypeAdapter extends XmlAdapter<AdaptedNum, NumItemType> {
#Override
public NumItemType unmarshal(AdaptedNum an) throws Exception {
NumItemType nit = new NumItemType();
nit.setNum(an.getNum);
nit.setPrecision(an.getPrecision);
nit.setDecimals(an.getDecimals)
return nit;
}
}
AdaptedNum.class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "adaptedNum", namespace = "", propOrder = {
"element1",
"element2",
"element3"
})
public class AdaptedNum {
#XmlElement(name ="element1")
protected BigDecimal num;
#XmlElement(name ="element2")
private String decimals;
#XmlElement(name ="element3")
private String precison;
// set/get method
}