Parsing optional nested XML Elements via JAXB - java

I have XML input that could basically look like this:
<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<object label="" Property1="43" id="2">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="196" y="161" width="200" height="30" as="geometry"/>
</mxCell>
</object>
<object label="" Property2="Helloooo" id="3">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="192" y="269" width="200" height="30" as="geometry"/>
</mxCell>
</object>
<object label="" Property3="23" id="4">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="210" y="383" width="200" height="30" as="geometry"/>
</mxCell>
</object>
</root>
</mxGraphModel>
I'm trying to parse this input via JAXB:
MxGraphModel.java:
#XmlRootElement(name = "mxGraphModel")
#XmlAccessorType(XmlAccessType.FIELD)
public class MxGraphModel {
#XmlElementWrapper(name = "root")
#XmlElement(name = "object")
private ArrayList<MxObject> mxObjects;
#XmlElement(name = "mxCell")
private ArrayList<MxCell> mxCells;
//getters and setters...
}
MxObject.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxObject {
#XmlAttribute
private String id;
#XmlAttribute
private String label;
#XmlAttribute
private String documentName;
#XmlAttribute
private String documentDescription;
#XmlElement
private MxCell mxCell;
//getters and setters...
}
MxCell.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxCell {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlAttribute
private String value;
#XmlAttribute
private String style;
#XmlAttribute
private String vertex;
#XmlElement(name = "mxGeometry")
private MxGeometry geometry;
//getters and setters...
}
DemoController.java:
#RestController
#RequestMapping("/xml")
public class DemoController {
#RequestMapping(method = RequestMethod.POST, consumes = {MediaType.APPLICATION_XML_VALUE})
public void parseXML(#RequestBody MxGraphModel mxGraphModel) {
//mxGraphModel contains EITHER objects of type MxObject
//OR
//MxCell
}
}
My problem is, that the parsing operation results in an MxGraphModel object that contains either a collection of objects OR a collection of mxCells - but never both.
It seems to me that the order in which I declare the XmlElements ("object" and "mxCell") is relevant for the parsing result. When I declare mxCell before object, 2 mxCells are being parsed (which is correct), but the object collection remains null. And the other way around.
Is it possible to have both XmlElements parsed? I don't know whether the issue is related to the fact that an object element could contain an mxCell element itself...
Thanks.

#Dimpre Jean-Sébastien:
You're totally right, sorry for posting the answer this late.
The solution is not to use the root ElementWrapper
So instead of using
#XmlElementWrapper(name = "root")
I had to create a root XmlElement in MxGraphModel.java:
#XmlElement(name = "root")
private MxRoot mxRoot;
Furthermore I created a file called MxRoot.java and moved all collections inside it:
MxRoot.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxRoot {
#XmlElement(name = "UserObject")
private ArrayList<MxObject> mxUserObjects;
#XmlElement(name = "object")
private ArrayList<MxObject> mxObjects;
//XmlElement sets the name of the entities
#XmlElement(name = "mxCell")
private ArrayList<MxCell> mxCells;
//getters and setters...
}
It seems the #XmlWrapper Annotation expects exactly one collection. It is not meant to wrap around multiple collections (makes sense now that I know it :))
Thanks to all!

Related

Jackson XML ArrayList output having two wrapper elements

I am getting two wrapper elements in the XML output generated by Jackson.
I would like to have only one.
I have a Java bean
#Entity
#Table(name = "CITIES")
#JacksonXmlRootElement(localName = "City")
public class City implements Serializable {
private static final long serialVersionUID = 21L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JacksonXmlProperty(isAttribute = true)
private Long id;
#JacksonXmlProperty
private String name;
#JacksonXmlProperty
private int population;
// getters, setters etc
}
and a List wrapper class.
#JacksonXmlRootElement
public class Cities implements Serializable {
private static final long serialVersionUID = 22L;
#JacksonXmlProperty(localName = "City")
#JacksonXmlElementWrapper(localName = "MyCities")
private List<City> cities = new ArrayList<>();
public List<City> getCities() {
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
}
I am getting this output, which has two wrapper elements. I would like
to remove one of them.
<Cities>
<MyCities>
<City id="1">
<name>Bratislava</name>
<population>432000</population>
</City>
<City id="2">
<name>Budapest</name>
<population>1759000</population>
</City>
<City id="3">
<name>Prague</name>
<population>1280000</population>
</City>
<MyCities>
</Cities>
One of them comes from the ArrayList, one from the class. How to get rid of one of the wrapper elements?
What I want to have is this:
<Cities>
<City id="1">
<name>Bratislava</name>
<population>432000</population>
</City>
<City id="2">
<name>Budapest</name>
<population>1759000</population>
</City>
<City id="3">
<name>Prague</name>
<population>1280000</population>
</City>
</Cities>
"Cities" is the root element, not a wrapper. Wouldn't removing the actual wrapper element "MyCities" work?
Adding #JacksonXmlElementWrapper(useWrapping = false) could also help.
Replacing #JacksonXmlElementWrapper(localName = "MyCities") with #JacksonXmlElementWrapper(useWrapping = false) in Cities should remove the additional wrapper element.
From the documentation:
#JacksonXmlElementWrapper
Allows specifying XML element to use for
wrapping List and Map properties; or disabling use (with 'useWrapping'
set to false).
The fix implemented in Cities:
#JacksonXmlRootElement
public class Cities implements Serializable {
private static final long serialVersionUID = 22L;
#JacksonXmlProperty(localName = "City")
#JacksonXmlElementWrapper(useWrapping = false)
private List<City> cities = new ArrayList<>();
public List<City> getCities() {
return cities;
}
public void setCities(List<City> cities) {
this.cities = cities;
}
}
You could also disable the wrapping functionality directly in the mapper with mapper.setDefaultUseWrapper(false);.
In this case you should simply remove #JacksonXmlElementWrapper(localName = "MyCities") from cities.

JAXB: how to unmarshal a List of objects of different types inside a wrapper?

I'm stucked at parsing the following xml with JAXB:
<?xml version="1.0" encoding="utf-8"?>
<dashboardreport name="exampleDashboard" version="6.5.6.1013" reportdate="2016-12-16T11:05:19.329+01:00" description="">
<data>
<incidentchartdashlet name="Incident Chart" description="" />
<chartdashlet name="WebRequestTime" showabsolutevalues="false" />
<chartdashlet name="WebServiceTime" showabsolutevalues="false" />
</data>
</dashboardreport>
I used the following java classes to unmarshal the xml:
Dashboardreport.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElement(name = "chartdashlet")
protected List<Chartdashlet> chartdashlets;
#XmlElementWrapper(name = "data")
#XmlElement(name = "incidentchartdashlet")
protected List<Incidentchartdashlet> incidentchartdashlets;
#XmlAttribute(name = "name")
protected String name;
}
I just want to unmarshal the xml without using a wrapper class around incidentchartdashlets and chartdashlet, cause both types differ a lot.
I only can use the XmlElementWrapper annotation once, so that only chartdashlets get filled and incidentchartdashlets is null.
Is there any solution with JAXB without using a seperate wrapper class?
I assume your dashlet classes are defined like
class Chartdashlet extends Dashlet and class Incidentchartdashlet extends Dashlet.
Then the preferred JAXB way to handle your mixed list of dashlets would be
by using the #XmlElements
annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElements({
#XmlElement(name = "chartdashlet", type = Chartdashlet.class),
#XmlElement(name = "incidentchartdashlet", type = Incidentchartdashlet.class)
})
protected List<Dashlet> dashlets;
#XmlAttribute(name = "name")
protected String name;
}

Multiple XML tag by JAXB

I'm using JAXB for generating XML, like this:
<Country>
<City>..</City>
<Adr>...</Adr>
</Country>
I have special class, which generate this XML:
#XmlElement(name = "Country")
private String country;
#XmlElement(name = "City")
private String city;
#XmlElement(name = "Adr")
private String adr;
with setters and getters, of course. But, how need I change this code, if I want to see XML like this?
<Country>
<City>..</City>
<Adr>...</Adr>
<City>..</City>
<Adr>...</Adr>
</Country>

How to generate xml tag as full class name using jaxb?

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<batch-execution>
<insert out-identifier="employee" return-object="true" entry-point="DEFAULT">
<fact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="employee">
<name>Rajashekhar</name>
<age>21</age>
</fact>
</insert>
<fire-all-rules></fire-all-rules>
</batch-execution>
Now I am getting this output as above but I want out put like below
<batch-execution>
<insert out-identifier="employee" return-object="true"
entry-point="DEFAULT">
<com.practise.Employee>
<name>Rajashekhar</name>
<age>21</age>
</com.practise.Employee>
</insert>
<fire-all-rules />
</batch-execution>
My Jaxb classes are
Request.java
#XmlRootElement(name = "batch-execution")
#XmlAccessorType(XmlAccessType.FIELD)
public class Request implements Serializable {
#XmlElement(name = "insert")
private List<Insert> insert;
#XmlElement(name = "fire-all-rules",nillable=true)
private String fireAllRules = "";
.
..
setters and getter
Insert.java
#XmlAccessorType(XmlAccessType.FIELD)
public class Insert {
#XmlAttribute(name = "out-identifier", required = true)
private String outIdentifier;
#XmlAttribute(name = "return-object")
private boolean returnObject;
#XmlAttribute(name = "entry-point")
private String entryPoint;
private Object fact;
.
.
setters and gettes
com.practise.Employee.java
#XmlRootElement(name="kewill.com.kewill.practoise.Employee")
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee implements java.io.Serializable
{
static final long serialVersionUID = 1L;
#org.kie.api.definition.type.Label("Name")
private java.lang.String name;
#org.kie.api.definition.type.Label("Id")
private java.lang.Integer id;
#org.kie.api.definition.type.Label("Age")
private int age;
#org.kie.api.definition.type.Label(value = "valid")
private java.lang.Boolean valid;
.
. setters and getters
I think it is possible through xtream api but I want to use JAXB please provide me the solution in jaxb.
In Insert.java
added Annotation for
private Object fact;
as
#XmlAnyElement(lax = true)
private Object fact;
Now it is giving expected output.

create nested structure using JAXB notations

<?xml version='1.0'?>
<info>
<contract>
<symbol>IBM</symbol>
<sectype>STK</sectype>
<exchange>SMART</exchange>
<currency>USD</currency>
</contract>
<order>
<action>SELL</action>
<quantity>100</quantity>
<ordertype>LMT</ordertype>
<imtprice>imtprice</imtprice>
<transmit>false</transmit>
</order>
</info>
I want to use jaxb annotations with existing java classes to create above XML input but i don't know how create nested xml structure based on Java classes
Try this:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder =
{"contract", "order"}) public class Info
{ #XmlElement(required =
true) private Contract
contract; #XmlElement(required = true) private Order order;
// Getters and setters }
Another class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"symbol",
"sectype", "exchange",
"currency"}) public class
Contract { #XmlElement(required
= true) private String symbol; #XmlElement(required =
true) private String
sectype; #XmlElement(required =
true) private String
exchange; #XmlElement(required
= true) private String currency; //Getters and
setters}
Create an order class the same way.

Categories

Resources