jaxb, how to get rid of unnecessary wrapping classes - java

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.

Related

How can I haver property order in JAXB with nested list and objects

I would like to ask on how to marshal an object with property order from a nested object.
#XmlRootElement(name = "sample")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"title", "code"})
public class SampleObject {
#XmlAttribute(name = "title")
private String title;
#XmlAttribute(name = "code")
private String code;
}
I have a wrapperList to set that object:
#XmlRootElement(name = "listWrapper")
#XmlAccessorType(XmlAccessType.FIELD)
public class WrapperObject {
#XmlAnyElement(lax=true)
private List<SampleObject> objectList;
}
And i want to set the list on this object. This object is the one who is being marshalled.
#XmlRootElement(name = "marshaller")
#XmlAccessorType(XmlAccessType.FIELD)
public class MarshallerObject {
#XmlElement(name = "wrapperList")
private WrapperObject objectList;
}
This is the output that i'm aiming for:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<marshaller>
<wrapperList>
<sample title="sampleTitle code"001"/>
</wrapperList>
</marshaller>
</soap:Envelope>
Thanks in advance!

Unable to Unmarshal XML response using JAXB classes

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.

How do I get the list of fieldname/elements from a JAXB generated java file?

I'm trying to figure out how to get the list of elements (all the names in the 'propOrder') from an auto-generated Java file that was created using JAXB. I want something along the lines of:
List String> elements = getXMLElements(ExampleInfo.class);
I can't edit the generated java class because the XSD schema might be changed. I'm trying to get the elements which would be startTime, stopTime, and id.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "exampleInfo", propOrder = {
"startTime",
"stopTime",
"id",
...
})
public class ExampleInfo
extends TypeInfo
{
#XmlElement(name = "StartTime")
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar startTime;
#XmlElement(name = "StopTime")
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar stopTime;
#XmlElement(name = "id")
...
}
You can do it quite easily with the help of method Class.getAnnotation(Class<A>):
public static List<String> getXMLElements(Class<?> clazz) {
XmlType xmlType = clazz.getAnnotation(XmlType.class);
if (xmlType == null)
return null;
String[] propOrder = xmlType.propOrder();
return Arrays.asList(propOrder);
}
Then use it like this:
List<String> elements = getXMLElements(ExampleInfo.class);

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

Categories

Resources