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;
Related
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.
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.
I have a dtd file and i used jaxb to generate java classes.
<!ELEMENT Conf (Node+) >
<!ELEMENT Node EMPTY >
<!ATTLIST Node Key CDATA #REQUIRED
Value CDATA #REQUIRED >
jaxb generated this.
Conf class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"node"
})
#XmlRootElement(name = "Conf")
public class Conf {
#XmlElement(name = "Node", required = true)
protected List<Node> node;
Node class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "Node")
public class Node {
#XmlAttribute(name = "Key", required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String key;
#XmlAttribute(name = "Value", required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String value;
For me is the Node class pointless and i'd like to have a map instead:
public class Conf {
protected Map<String,String> map
}
I guess that im looking for XmlAdater, i've read javadocs but i still have problems to understand how it works.
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
Im having this error where it says that i have two classes of same XML type name
so the problem is between InfoSource -> NameSearchFilters -> SearchRequest
error
Caused by: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://test.au/schema/namesearch}InfoSource". Use #XmlType.name and #XmlType.namespace to assign different names to them.
this problem is related to the following location:
at au.test.identitySearch.model.InfoSource
at protected au.test.identitySearch.model.InfoSource au.test.identitySearch.model.nameSearch.NameSearchFilters.infoSourceList
at au.test.identitySearch.model.nameSearch.NameSearchFilters
this problem is related to the following location:
at au.test.identitySearch.model.InfoSource
at protected au.test.identitySearch.model.InfoSource au.test.identitySearch.model.nameSearch.NameSearchFilters.infoSourceList
at au.test.identitySearch.model.nameSearch.NameSearchFilters
at protected au.test.identitySearch.model.nameSearch.NameSearchFilters au.test.identitySearch.ws.model.SearchRequest.searchFilters
at au.test.identitySearch.ws.model.SearchRequest
InfoSource
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "InfoSource", propOrder = {
"infoSource"
})
public class InfoSource {
#XmlElement
protected List<String> infoSource;
NameSearchFilters
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NameSearchFilters", propOrder = {
})
public class NameSearchFilters {
#XmlElement
protected InfoSource infoSourceList;
#XmlElement
protected String nameType;
SearchRequest
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"searchControls",
"searchCriteria",
"searchFilters"
})
#XmlRootElement(name = "searchRequest")
public class SearchRequest {
#XmlElement(required = true)
protected SearchControls searchControls;
#XmlElement(required = true)
protected NameSearchCriteria searchCriteria;
#XmlElement
protected NameSearchFilters searchFilters;
Why is there problem here?
Did you try adding different values of namespace attribute to each of them like #XmlType(namespace="test1", name = "InfoSource", propOrder = { "infoSource" }) ) ?
Situation like this throws exception 'x counts of IllegalAnnotationExceptions'
class A{}
class B extends A{}
class C extends A{}
Resolve problem adding annotation into class A like this:
#XmlTransient
public class A{}
#XmlType(name = "Info_Source", propOrder = {
"infoSource"
Try this in code