Unable to Unmarshal XML response using JAXB classes - java

Exception :
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.cleartrip.com/hotel/hotel-search-response", local:"hotel-search-response"). Expected elements are (none)
MyTestFile.txt(XML) :
<hotel-search-response xmlns="http://www.cleartrip.com/hotel/hotel-search-response" xmlns:hotel-info="http://www.cleartrip.com/places/hotel-info" xmlns:common="http://www.cleartrip.com/hotel/common">
<search-criteria>
<booking-date>2018-12-12+05:30</booking-date>
<check-in-date>2018-12-14+05:30</check-in-date>
<check-out-date>2018-12-16+05:30</check-out-date>
<number-of-rooms>1</number-of-rooms>
<number-of-nights>2</number-of-nights>
<number-of-room-nights>2</number-of-room-nights>
<city>Bangalore</city>
<country>IN</country>
</search-criteria>
<currency>INR</currency>
JAXB Class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "hotel-search-response", propOrder = {
"searchCriteria",
"additionalCurrency",
"currency",
"baseUrl",
"hotels",
"pgfeeJson",
"pgchargeJson"
})
public class HotelSearchResponse {
#XmlElement(name = "search-criteria", required = false)
protected SearchCriteria searchCriteria;
#XmlElement(name = "additional-currency",required= false)
protected AdditionalCurrency additionalCurrency;
#XmlElement(required = false)
protected String currency;
#XmlElement(name = "base-url", required = false)
protected String baseUrl;
#XmlElement(required = false)
protected Hotels hotels;
#XmlElement(name = "pgfee-json", required = false)
protected String pgfeeJson;
#XmlElement(name = "pgcharge-json", required = false)
protected String pgchargeJson;
}
Java main class:
JAXBContext jc= JAXBContext.newInstance(HotelSearchResponse.class);
javax.xml.bind.Unmarshaller ums = jc.createUnmarshaller();
HotelSearchResponse emp=(HotelSearchResponse) ums.unmarshal(new File("E:/MyTestFile.txt"));

First, you need the have a #XmlRootElement. Second, you need to specify the namespace (since you use namespaces).
#XmlRootElement(name = "hotel-search-response", namespace = "http://www.cleartrip.com/hotel/hotel-search-response")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "hotel-search-response", propOrder = { "currency", "baseUrl",
"pgfeeJson", "pgchargeJson" }, namespace = "http://www.cleartrip.com/hotel/hotel-search-response")
public class HotelSearchResponse
Above, the propOrder is simplified.

Related

Java - How to set propOrder attribute dynamically within #XmlType

I have a class with xml annotations that will be instantiated then used to generated a xml file.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"foo", "bar", "baz"
})
public class MyClass {
#XmlElement(name = "foo", required = true)
protected String foo;
#XmlElement(name = "bar", required = true)
protected String bar;
#XmlElement(name = "baz", required = true)
protected String baz;
...
}
I would like to set the attribute propOrder dynamically using a variable (version for example) like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = version.equals("1") ? {"foo", "bar", "baz"} : {"bar", "baz", "foo"}
)
public class MyClass {
#XmlElement(name = "foo", required = true)
protected String foo;
#XmlElement(name = "bar", required = true)
protected String bar;
#XmlElement(name = "baz", required = true)
protected String baz;
...
}
So based on this version parameter, the xml file generated will look like
<foo></foo>
<bar></bar>
<baz></baz>
or
<bar></bar>
<baz></baz>
<foo></foo>
Any idea?
It is impossible. Annotations are handled in compile time.
PS: It is impossible in pure java. If you really want you can use some kind of preprocessor.

Camel don't want to print POJO in java DSL route

I'm trying to use Apache Camel to parse XML to POJO and have problem with printing out the actual POJO. Instead I get regular XML as if no convertation not happening. When I pass for example Customer insted of Customers its working okay. Also printing Customers class to sout in bean warks perfectly.
MyRoute
#Autowired
private MyBean mb;
#Override
public void configure() throws Exception {
from("file:{{customer.path}}?noop=true")
.bean(mb)
.to("stream:out");
}
MyBean
#Handler
public Customers whatIsInBody(Customers body) {
return body;
}
POJO classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"customer"
})
#XmlRootElement(name = "customers")
public #Data
class Customers {
#XmlElement(required = true, nillable = true)
protected List<Customer> customer;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "customer", propOrder = {
"id",
"name",
"adress",
"countryCode",
"products"
})
public #Data
class Customer {
protected long id;
#XmlElement(required = true)
protected String name;
#XmlElement(required = true)
protected String adress;
#XmlElement(required = true)
protected String countryCode;
#XmlElement(required = true, nillable = true)
protected List<Product> products;
}
Output example:
<customers>
<customer>
<id>12345</id>
<name>str1234</name>
<adress>str1234</adress>
<countryCode>str1234</countryCode>
<products>
<id>12345</id>
<name>str1234</name>
</products>
</customer>
Desired output:
Customers(customer=[Customer(id=12345, name=str1234, adress=str1234, countryCode=str1234, products=[Product(id=12345, name=str1234)]),
When you have camel-jaxb on the classpath, then a POJO class with JAXB annotations is type converted to XML when you convert it to a String type, which is what the stream:out would do.
You can enable the tracer to see what the message contains during routing
http://camel.apache.org/tracer
So if you really want to stream:out the toString of the message body, you would need to transform it manually first, by calling its toString method
.transform(simple("${body.toString()}"))

Jaxb: namespace unmarshalling issue

all, I have a package full of Beans generated from xsd with Jaxb.
I want to use some of them into another Bean to marshal/unmarshal an XML like this:
<WrongDocument>
<test>test label</test>
<CBISDDReqLogMsg xmlns="urn:CBI:xsd:CBISDDReqLogMsg.00.01.00">
<GrpHdr>
....
</GrpHdr>
<PmtInf>
</PmtInf>
</CBISDDReqLogMsg>
</WrongDocument>
the root Bean is
#XmlRootElement(name="WrongDocument")
#XmlType(name = "", propOrder = {
"test",
"CBISDDReqLogMsg"
})
#XmlAccessorType(XmlAccessType.FIELD)
public class WrongDocumentDTO implements Serializable {
private static final long serialVersionUID = 8545918230166653233L;
#XmlElement(required = true, type = String.class, nillable = true)
protected String test;
#XmlElement(required = true)
protected CBISDDReqLogMsg000100 CBISDDReqLogMsg;
....
}
and the CBISDDReqLogMsg000100 is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CBISDDReqLogMsg.00.01.00", propOrder = {
"grpHdr",
"pmtInf"
})
public class CBISDDReqLogMsg000100
implements Serializable
{
private final static long serialVersionUID = 1L;
#XmlElement(name = "GrpHdr", required = true)
protected CBIGroupHeader2 grpHdr;
#XmlElement(name = "PmtInf", required = true)
protected List<PaymentInstructionInformation2> pmtInf;
....
}
For CBISDDReqLogMsg000100 namespace is defined with package-info file.
This is the code for unmarshalling:
jc = JAXBContext.newInstance(WrongDocumentDTO.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
WrongDocumentDTO wrongDocumentDTO = unmarshaller.unmarshal(source, WrongDocumentDTO.class).getValue();
Unfortunately, inside my wrongDocumentDTO i have test field populated with the right value, however CBISDDReqLogMsg is null.
How can i resolve this issue?
thank you in advance
You will need to specify the namespace specifically on the element if it is not default for the whole package.
#XmlElement(required = true, namespace = "urn:CBI:xsd:CBISDDReqLogMsg.00.01.00")
protected CBISDDReqLogMsg000100 CBISDDReqLogMsg;

JAXB - unmarshalled fields are null

We are unmarshalling a response from http://xmlgw.companieshouse.gov.uk/. This is the text sent to the marshall:
<NameSearch xmlns="http://xmlgw.companieshouse.gov.uk/v1-0/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlgw.companieshouse.gov.uk/v1-0/schema http://xmlgw.companieshouse.gov.uk/v1-0/schema/NameSearch.xsd">
<ContinuationKey>...</ContinuationKey>
<RegressionKey>...</RegressionKey>
<SearchRows>20</SearchRows>
<CoSearchItem>
<CompanyName>COMPANY NAME</CompanyName>
<CompanyNumber>23546457</CompanyNumber>
<DataSet>LIVE</DataSet>
<CompanyIndexStatus>DISSOLVED</CompanyIndexStatus>
<CompanyDate></CompanyDate>
</CoSearchItem>
// more CoSearchItem elements
</NameSearch>
The model of CoSearchItem is like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CoSearchItem", propOrder = {
"companyName",
"companyNumber",
"dataSet",
"companyIndexStatus",
"companyDate",
"searchMatch"
})
public class CoSearchItem {
#XmlElement(name = "CompanyName", required = true)
protected String companyName;
#XmlElement(name = "CompanyNumber", required = true)
protected String companyNumber;
#XmlElement(name = "DataSet", required = true)
protected String dataSet;
#XmlElement(name = "CompanyIndexStatus")
protected String companyIndexStatus;
#XmlElement(name = "CompanyDate")
#XmlSchemaType(name = "date")
protected XMLGregorianCalendar companyDate;
#XmlElement(name = "SearchMatch")
protected String searchMatch;
// getters and setters
}
NameSearch model has this structure:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NameSearch", namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema", propOrder = {
"continuationKey",
"regressionKey",
"searchRows",
"coSearchItem"
})
#XmlRootElement(name = "NameSearch", namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema")
public class NameSearch {
#XmlElement(name = "ContinuationKey", required = true)
protected String continuationKey;
#XmlElement(name = "RegressionKey", required = true)
protected String regressionKey;
#XmlElement(name = "SearchRows", required = true)
protected BigInteger searchRows;
#XmlElement(name = "CoSearchItem")
protected List<CoSearchItem> coSearchItem;
// setters and getters
}
The package has this annotations:
#XmlSchema(namespace = "http://xmlgw.companieshouse.gov.uk/v1-0", elementFormDefault = XmlNsForm.QUALIFIED, //
xmlns = {
#XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
}
)
package uk.gov.companieshouse;
The unmarshaling is done from the first Node extracted from a larger Document, inside an any list of items. When we parse the xml however all the fields in CoSearchItem are set to null and can't figure out the reason.
You need to use a package level #XmlSchema annotation to specify the namespace qualification for your model.
#XmlSchema(
namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
This this specified you do not require to specify the namespace URI on the #XmlRootElement and #XmlType on your NameSearch class.
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
The unmarshaling is done from the first Node extracted from a larger
Document, inside an any list of items.
Make sure the DOM parer used to create the nodes is namespace aware.
documentBuilderFactory.setNamespaceAware(true);
I figured out the correct answer thanks to #Blaise Doughan. After looking at the package namespace qualification I found that it was pointing to:
"http://xmlgw.companieshouse.gov.uk/v1-0"
and it should have been pointing to:
"http://xmlgw.companieshouse.gov.uk/v1-0/schema"
Not sure how that got misplaced.
I solved this by making elementFormDefault="unqualified" in the xsd before generating stubs, else make the change manually in package-info.java

jaxb unmarshalling returns null

I'm unmarshalling a response for soap message like the following
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<m:soResponse SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:m="urn:tec">
<Error/>
<Order>
<Number>6</Number>
</Order>
</m:soResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
and i'm binding the jaxb annotation as
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"body"
})
#XmlRootElement(name = "Envelope")
public class Envelope {
#XmlElement(name = "Body", namespace = "http://schemas.xmlsoap.org/soap/envelope/", required = true)
protected Body body;
//......
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"soResponse"
})
#XmlRootElement(name = "Body")
public class Body {
#XmlElement(namespace = "http://schemas.xmlsoap.org/soap/envelope/", required = true)
protected soResponse;
//-----------
}
XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"error",
"order"
})
#XmlRootElement(name = "soResponse")
public class soResponse{
#XmlElement(name = "Error", required = true)
protected soResponse.Error error;
#XmlElement(name = "Order", required = true)
protected soResponse.Order order;
#XmlAttribute(name = "encodingStyle", namespace = "http://schemas.xmlsoap.org/soap/envelope/", required = true)
#XmlSchemaType(name = "anyURI")
protected String encodingStyle;
//-----------------------
}
the problem is, that i'm getting soResponse always null !!?
It looks like you've got the wrong namespace on your
#XmlElement(namespace = "http://schemas.xmlsoap.org/soap/envelope/", required = true)
protected soResponse;
This would look for a <SOAP-ENV:soResponse>, not a <m:soResponse xmlns:m="urn:tec">.

Categories

Resources