Pulling XML child inner node from XML to Java Object using JAXB - java

I have been trying to pull a child node from an XML which I received from a SOAP as string. I can retrieve the parent node but couldn't retrieve the child node. I also surf the internet to see if I can get an answer but all to no avail. I saw some examples with direct child pulling, but that didn't solve my problem.
<response>
<code>1</code>
<list available="2">
<cart id="2" name="egg">
<stuff>
<id>001</id>
<name>Crew</name>
<shortname>C</shortname>
</stuff>
</cart>
<cart id="4" name="bread">
<stuff>
<id>004</id>
<name>Bread</name>
<shortname>B</shortname>
</stuff>
</cart>
</list>
</response>
Response Class
public class Response {
private String code;
private String list;
private String cart;
private Response.Stuff stuffs;
#XmlElement(name="code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
.
.
#XmlElement
public Response.Stuff getStuff() {
return this.stuffs;
}
public void setStuff(Response.Cart stuff) {
this.stuffs = stuff;
}
public static class Stuff {
private List<Stuff> stuff;
public List<Stuff> getStuff() {
if (stuff == null) {
stuff = new ArrayList<Stuff>();
}
return stuff;
}
}
}
Stuff Classs
public class Stuff {
private String id;
private String crew;
#XmlElement
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
.
.
}
Now my problem is how to pull child stuff content (i.e id,name and shortname) using JAXB.
I created class Response and Stuff and made stuff a list inside response but when ever I run the code it throws null exception.
PS: Please remember the XML is not a file its a string and am using StringReader class for the JAXB.unmarshal

JAXBContext jcontext= JAXBContext.newInstance();
unmarshaller um=jcontext.createUnmarshaller();
JAXBElement je=um.unmarshal(new File("pass xml file location"));
response r= getValue();
r.getlist().getcart().getstuff().getid().getValue();
try this one it may work

I finally solved my problem by restructuring the above class and creating a new one. See below the updated:
public class Response {
private String code;
private List list;
#XmlElement(name="code")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#XmlElement(name= "list")
public List getlist() {
return this.list;
}
public void setList(List list) {
this.list = list;
}
}
Class List
#XmlRootElement(name= "list")
public class List {
private List.Cart cart;
#XmlElement(name= "cart")
public List<Cart> getCart() {
return this.cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
#XmlRootElement(name= "cart")
public static class Cart {
private List<Stuff> stuff;
private List<Stuff> getStuff() {
if (stuff == null) {
stuff = new ArrayList();
}
return stuff;
}
}
}
With this, it was easy for me to marshal and unmarshal

Related

How to convert Java objects to XML element attributes using JAXB

How to convert java object to xml using JAXB to get the following xml:
<Case>
<Version>1.0</Version>
<Code>457123</Code>
<Meta uc=\"Sample\" pip=\"116.0.1.1\" lot=\"P\"/>
</Case>
There are many answers regarding how to get XML. I have gone through all those. But my question is how to get the XML as what I have shown. It contains a self-closing tag which even contains attributes.
I am using Eclipse IDE. Please suggest a method.
This is my case class:
import auth.Res.Meta;
#XmlRootElement (name="Case")
public class Test {
private Meta mt;
private String version;
private String code;
#XmlRootElement
public class Meta {
#XmlAttribute
private String uc;
#XmlAttribute
private String pip;
public String getUc() {
return uc;
}
public void setUc(String uc) {
this.uc = uc;
}
public String getPip() {
return pip;
}
public void setPip(String pip) {
this.pip = pip;
}
}
public Meta getMt() {
return mt;
}
public void setMt(Meta mt) {
this.mt = mt;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
Solution:
I solved it by creating seperate class for Meta as suggested by LazerBanana in the first answer.
This is how your Meta class should look like.
public class Meta {
private String uc;
private String pip;
private String lot;
public String getUc() {
return uc;
}
#XmlAttribute
public void setUc(String uc) {
this.uc = uc;
}
public String getPip() {
return pip;
}
#XmlAttribute
public void setPip(String pip) {
this.pip = pip;
}
public String getLot() {
return lot;
}
#XmlAttribute
public void setLot(String lot) {
this.lot = lot;
}
}
this is your Case class which is the root element
#XmlRootElement
public class Case {
private int version;
private String code;
private String id;
private Meta meta;
public int getVersion() {
return version;
}
#XmlElement
public void setVersion(int version) {
this.version = version;
}
public String getCode() {
return code;
}
#XmlElement
public void setCode(String code) {
this.code = code;
}
public String getId() {
return id;
}
#XmlElement
public void setId(String id) {
this.id = id;
}
public Meta getMeta() {
return meta;
}
#XmlElement
public void setMeta(Meta meta) {
this.meta = meta;
}
}
And this is the marshaling bit to the console and to the file it you want.
public class Main {
public static void main(String... args) {
Case fcase = new Case();
Meta meta = new Meta();
meta.setLot("asd");
meta.setPip("sdafa");
meta.setUc("asgd4");
fcase.setMeta(meta);
fcase.setVersion(1);
fcase.setId("sah34");
fcase.setCode("code34");
try {
// File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Case.class, Meta.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// jaxbMarshaller.marshal(fcase, file);
jaxbMarshaller.marshal(fcase, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Output:
<case>
<code>code34</code>
<id>sah34</id>
<meta lot="asd" pip="sdafa" uc="asgd4"/>
<version>1</version>
</case>
Next time please try to do more research i am not an expert and I just googled it.
https://www.mkyong.com/java/jaxb-hello-world-example/
i need to create a rest service which accepts xml of format i have gien. Thats y i need it in a single class.
#POST
#Path("/add")
#Consumes("application/xml")
#Produces("application/xml")
public Response getper(Test test)
{
String nam=test.getVersion();
int cd=test.getCode();
Res rs=new Res();
rs.setMessage(nam);
.
.
return Response.status(200).entity(rs).build();
}

Java - Getting a ElementList attribute with SimpleXML (Android/Retrofit)

I'm trying to parse an XML response that looks like this with SimpleXML. It's very similar to the example shown at the simple xml tutorial page
http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php#javabean
<response>
<version>1.0</version>
<code>1</code>
<message>Report generated</message>
<records total="365">
<record rowId="1" data1="1234" data2="abc" />
<record rowId="2" data1="5678" data2="def" />
<record rowId="3" data1="9012" data2="ghi" />
</records>
</response>
The only difference I have, is my <records total="365"> tag has an attribute I need to collect so I can determine if there's multiple pages of results.
I've tried using their example, which resulted in this
public class Response {
private ArrayList<Record> records;
#Element
public String message;
#Element
public String code;
#Element
public String version;
#ElementList
public void setRecords(ArrayList<Record> records) {
if(records.isEmpty()) {
throw new IllegalArgumentException("Empty collection");
}
this.records = records;
}
#ElementList
public ArrayList<Record> getRecords() {
return records;
}
public class Record {
#Attribute public String data1;
#Attribute public String data2;
}
}
Aside from missing the Total attribute in the Records tag, this works correctly.
Whatever I try to do to get this Total tag out doesn't work though.
I've tried all sorts of combinations of making a Records class that holds the attribute and ArrayList instead, having it in the main object as a basic attribute, or trying to have a getter / setter in the main response object without any luck.
E.G.
public class Response {
#Element
public String message;
#Element
public String code;
#Element
public String version;
#Element
public Records records;
public class Records{
private ArrayList<Record> records;
#Attribute
public String total;
#ElementList
public void setRecords(ArrayList<Record> records) {
if(records.isEmpty()) {
throw new IllegalArgumentException("Empty collection");
}
this.records = records;
}
#ElementList
public ArrayList<Record> getRecords() {
return records;
}
}
public class Record {
#Attribute public String data1;
#Attribute public String data2;
}
}
I don't understand how to make the List object, and get an attribute from it.
Any help would be greatly appreciated, I'm not sure how to make it work, it seems like it should be so simple, but I'm obviously missing something.
Was able to get some help and this is what works
#Default(DefaultType.FIELD)
public class Response{
public String message;
public String code;
public String version;
public Records records;
public Records getRecords ()
{
return records;
}
public void setRecords (ArrayList<Record> records)
{
this.records.setRecord(records);
}
}
public class Records
{
#Attribute
public String total;
public ArrayList<Record> records;
public String getTotal ()
{
return total;
}
public void setTotal (String total)
{
this.total = total;
}
#ElementList(inline=true)
public ArrayList<Record> getRecord ()
{
return records;
}
#ElementList(inline=true)
public void setRecord (ArrayList<Record> record)
{
this.records = record;
}
}
public class Record {
#Attribute public String data1;
#Attribute public String data2;
}

Marshall a List to XML works - but how to unmarshall?

I can marshall a ObservableList using a "Wrapper"-class like below. But I cannot unmarshall it back to the wrapperclass it was before.
The idea is:
I have an ObservableList of "Expenses". I put this List into a wrapper-class and save this class to XML. The result looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<List>
<root>
<category>[none]</category>
<period>Year</period>
<title>asd</title>
<value>354</value>
</root>
</List>
I cannot bring it back to the wrapper-object.
I really appreciate any kind of help.
Main-class JAXBContext (visible for all):
JAXBContext jc = JAXBContext.newInstance(MyWrapperForList.class, Expense.class);
Main-class SAVEBUTTON:
public class SaveButtonListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent arg0) {
File serializedFile = new File(PATH);
try {
if (serializedFile.exists() == false)
serializedFile.createNewFile();
PrintWriter xmlOut = new PrintWriter(serializedFile);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
List<Expense> saveList = new ArrayList<>();
saveList.addAll(data);
MyWrapperForList<Expense> wrapper = new MyWrapperForList<>(saveList);
JAXBElement<MyWrapperForList> jaxbElement = new JAXBElement<>(
new QName("List"), MyWrapperForList.class, wrapper);
m.marshal(jaxbElement, xmlOut);
xmlOut.flush();
xmlOut.close();
Main-class-LOADBUTTON:
public class LoadButtonListener implements EventHandler<ActionEvent> {
#Override
public void handle(ActionEvent arg0) {
try {
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource xml = new StreamSource(PATH);
MyWrapperForList<Expense> unwrapper = unmarshaller.unmarshal(xml,
MyWrapperForList.class).getValue();
List<Expense> tempList = new ArrayList<>();
tempList.addAll(unwrapper.getItems());
System.out.println(tempList.get(0).getTitle());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Wrapper-class:
public class MyWrapperForList {
private List<Expense> list;
public MyWrapperForList() {
list = new ArrayList<>();
}
public MyWrapperForList(List<Expense> expenses) {
this.list = expenses;
}
#XmlAnyElement(lax=true)
public List<Expense> getItems() {
return list;
}
}
Expense-class:
#XmlRootElement(name = "root")
public class Expense {
private String title;
private String category;
private String period;
private String value;
public Expense() {} //Default constructor is needed for XML-handling
public Expense(String title, String value, String period, String category) {
this.title = title;
this.value = value;
this.period = period;
this.category = category;
}
#XmlElement(name = "title")
public String getTitle() {
return this.title;
}
#XmlElement(name = "category")
public String getCategory() {
return this.category;
}
#XmlElement(name = "period")
public String getPeriod() {
return this.period;
}
#XmlElement(name = "value")
public String getValue() {
return this.value;
}
}
I used this tutorial from Blaise Doughan: http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
MyListWrapper
If you want MyWrapperForList to unmarshal holding an instance of ObservableList then you will need to setup your class in one of the following ways.
Property of Type ObservableList
import javax.xml.bind.annotation.XmlAnyElement;
import javafx.collections.*;
public class MyWrapperForList<T> {
private ObservableList<T> list;
public MyWrapperForList() {
list = FXCollections.<T>observableArrayList();
}
public MyWrapperForList(ObservableList<T> list) {
this.list = list;
}
#XmlAnyElement(lax = true)
public ObservableList<T> getItems() {
return list;
}
}
List Property Initialized to Instance of ObservableList
import java.util.List;
import javax.xml.bind.annotation.XmlAnyElement;
import javafx.collections.*;
public class MyWrapperForList<T> {
private List<T> list = FXCollections.<T>observableArrayList();
public MyWrapperForList() {
list = FXCollections.<T>observableArrayList();
}
public MyWrapperForList(List<T> list) {
this.list = list;
}
#XmlAnyElement(lax = true)
public List<T> getItems() {
return list;
}
}
Demo Code
Input (nub.xml)
<List>
<root>
<category>[none]</category>
<period>Year</period>
<title>dfg</title>
<value>4</value>
</root>
<root>
<category>[none]</category>
<period>Year</period>
<title>ROBO</title>
<value>1234</value>
</root>
</List>
Demo
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyWrapperForList.class, Expense.class);
//UNMARSHALLING
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource xml = new StreamSource("src/forum18594548/nub.xml");
MyWrapperForList<Expense> wrapper = (MyWrapperForList<Expense>) unmarshaller.unmarshal(xml, MyWrapperForList.class).getValue();
List<Expense> data = wrapper.getItems();
System.out.println(data.getClass());
for(Expense expense : data) {
System.out.println(expense);
}
}
}
Output
class com.sun.javafx.collections.ObservableListWrapper
forum18594548.Expense#789df61d
forum18594548.Expense#4a8927c8
UPDATE
First: Thanks for you work Blaise!! I'm really glad for what you do to
me! I tried what you wrote here (it was nearly the same as I had) and
I got a similar (same type of) output as you got. BUT the objects in
the lists are all referenced with null. If I write
System.out.println(data.get(0).getTitle()); it says null. There is the
exact amount of objects in the list, but all attributes are referenced
with null. :(
I think I got tunnel vision on the ObservableList aspect only to miss your real problem was with how you mapped the Expense class. Since you only have get methods you should map to the fields using #XmlAccessorType(XmlAccessType.FIELD) as follows.
import javax.xml.bind.annotation.*;
#XmlRootElement(name="root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Expense {
private String title;
private String category;
private String period;
private String value;
public Expense() {
}
public Expense(String title, String value, String period, String category) {
this.title = title;
this.value = value;
this.period = period;
this.category = category;
}
public String getTitle() {
return this.title;
}
public String getCategory() {
return this.category;
}
public String getPeriod() {
return this.period;
}
public String getValue() {
return this.value;
}
}

Jackson Json with nested parametric classes

Listing:
import java.util.List;
public class Listing<T> {
List<Thing<T>> children;
public List<Thing<T>> getChildren() {
return children;
}
public void setChildren(List<Thing<T>> children) {
this.children = children;
}
}
Thing:
public class Thing<T> {
private String type;
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
Link:
public class Link {
private String author;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
and here's an example of serialization and deserialization...
public static void main(String[] args) throws IOException {
Link link1 = new Link();
link1.setAuthor("JohnDoe");
Link link2 = new Link();
link2.setAuthor("MaryJane");
List<Thing<Link>> things = new ArrayList<Thing<Link>>();
Thing<Link> thing1 = new Thing();
thing1.setData(link1);
thing1.setType("t3");
Thing<Link> thing2 = new Thing();
thing2.setData(link2);
thing2.setType("t3");
things.add(thing1);
things.add(thing2);
Listing<Link> listing = new Listing<Link>();
listing.setChildren(things);
Thing<Listing> thing = new Thing<Listing>();
thing.setType("listing");
thing.setData(listing);
File jsonFile = new File("src/testMap.txt");
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(jsonFile, thing);
//String jsonString = "{\"type\":\"listing\",\"data\":{\"children\":[{\"type\":\"t3\",\"data\":{\"author\":\"JohnDoe\"}},{\"type\":\"t3\",\"data\":{\"author\":\"MaryJane\"}}]}}";
JavaType jsonType = mapper.getTypeFactory().constructParametricType(Thing.class, Listing.class);
Thing<Listing> readThing = mapper.readValue(jsonFile, jsonType);
}
The problem that I'm having is that the Things contained in the Listing in the sample code above are not parametrized with Link, so their data field is returned as an Object (which is actually LinkedHashMap).
I want to be able to do something like this:
List<Thing<Link>> readListingChildren = readThing.getData().getChildren();
String author = readListingChildren.get(0).getData().getAuthor();
My question is, how would I get this to work using Jackson json?
Note: there will be multiple different types of objects contained by Things, and a Thing's data member's type is defined (or should be defined) by the data object's "type" field, using strings such as t1, t2, t3, etc. which map to different classes.
To achieve a serialized String like
{
"data":{
"type":"listing",
"children":[
{
"data":{
"type":"t3",
"author":"JohnDoe"
}
},
{
"data":{
"type":"t3",
"author":"MaryJane"
}
}
]
}
}
and to use the type information to correctly deserialize the concrete class you may use
#JsonTypeName("listing")
public class Listing<T> {
List<Thing<T>> children;
public List<Thing<T>> getChildren() {
return children;
}
public void setChildren(final List<Thing<T>> children) {
this.children = children;
}
}
public class Thing<T> {
private T data;
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(Link.class),
#JsonSubTypes.Type(Listing.class)
})
public T getData() {
return data;
}
public void setData(final T data) {
this.data = data;
}
}
#JsonTypeName("t3")
public class Link {
private String author;
public String getAuthor() {
return author;
}
public void setAuthor(final String author) {
this.author = author;
}
}

XStream, CircularReferenceException

Please consider this code. Is it using Circular Reference? If not why am I getting CircularReferenceException, while enabling NO_REFERENCE mode in XStream. Anyone, please clarify the thing.
#XStreamAlias("BalanceEnquiry")
public class BalanceEnquiry extends EAIRequest {
#XStreamImplicit
private List<BalanceEnquiry.Detail> details;
public List<Detail> getDetails() {
....
}
public void setDetails(Detail... details) {
....
}
#XStreamAlias("details")
public final class Detail {
#XStreamAsAttribute
private String item;
private BalanceEnquiry.Detail.Request request;
public String getItem() {
....
}
public void setItem(String item) {
....
}
public Request getRequest() {
....
}
public void setRequest(Request request) {
....
}
public final class Request {
private String code;
private String branch;
public String getCode() {
....
}
public void setCode(String code) {
....
}
public String getBranch() {
....
}
public void setBranch(String branch) {
....
}
}
}
}
I suspect it's because Detail is an inner class. As such, it has an implicit reference to the instance of the outer class (and hence forms a circular reference). See here for more details.

Categories