jaxb delete list tag - java

I need to marshall a java class to get a xml, but i don't know how to delete a tag inside the one generated.
I have a class with an object list with this form
#XmlRootElement(name = "Element")
public class Element {
private List<Foo> foos;
#XmlElementWrapper("fooList")
public List<Foo> getfoos() {
return foos;
}
public void setFoos(List<Foo> foos) {
this.foos = foos;
}
}
And the class Foo of the list is lie this:
#XmlRootElement
public class Foo {
private String id;
private String code;
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
When marshalling to get xml I get this:
<Element>
<fooList>
<foos>
<string1>asd</string1>
<string2>qwe</string2>
</foos>
<foos>
<string1>poi</string1>
<string2>lkj</string2>
</foos>
</fooList>
</Element>
But I want to get it without the tag foos, like this:
<Element>
<fooList>
<string1>asd</string1>
<string2>qwe</string2>
<string1>poi</string1>
<string2>lkj</string2>
</fooList>
</Element>
Can anyone help me?
Thanks a lot!!

You could do something like this:
#XmlRootElement(name = "Element")
#XmlAccessorType(XmlAccessType.FIELD)
public class Element {
#XmlElementWrapper(name = "fooList")
#XmlElements({
#XmlElement(name = "id", type = Id.class),
#XmlElement(name = "code", type = Code.class),
})
private List<FooItem> foos;
public List<FooItem> getfoos() {
return foos;
}
public void setFoos(List<FooItem> foos) {
this.foos = foos;
}
}
and then Id and Code classes look similar:
public class Id implements FooItem {
#XmlValue
private String id;
public Id() {}
public Id(String id) {
this.id = id;
}
}
They are bounded by an interface that doesn't do much:
public interface FooItem { }
This structure will allow you to marshal into xml as the one you specified you need.
The challenge with the class structure you had is that class Foo had 2 fields and #XmlValue can be applied only to one field per class. So having 2 fields "forces" them to stand for #XmlElement and they in turn have to be children of an xml element. This is why you had the "intermediate" foo elements in your xml for each Foo instance in your List.

Related

How to use #XmlIDREF and #XmlID

I don't quite understand how #XmlIDREF and #XmlID work together. By using XmlIDREF I only create a reference to the actual element. However what is the use case for XmlID.
I want to create a reference to the class Publication. Is it enough to annotate the publication List with #XmlIDREF?
public class Author {
private String id;
private String name;
private List<Publication> publications = new LinkedList<>();
public Author() {
super();
}
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlIDREF
public List<Publication> getPublications() {
return publications;
}
I want to create a reference to the class Publication.
Is it enough to annotate the publication List with #XmlIDREF?
No, that's only one half of what you need.
You already have this:
With #XmlIDREF you mark the referencing side of the relation
(pointing from Author to Publication).
public class Author {
...
#XmlIDREF
#XmlElement(name = "publication")
public List<Publication> getPublications() {
return publications;
}
...
}
You also need to mark the referenced side (the Publication itself)
by annotating one of its properties with #XmlID, for example like this:
public class Publication {
...
#XmlID
#XmlElement
public String getId() {
return id;
}
...
}
Then you are able to process XML content like this example:
<root>
<publication>
<id>p-101</id>
<title>Death on the Nile</title>
</publication>
<publication>
<id>p-102</id>
<title>The murder of Roger Ackroyd</title>
</publication>
...
<author>
<id>a-42</id>
<name>Agatha Christie</name>
<publication>p-101</publication>
<publication>p-102</publication>
</author>
...
</root>
You see, the XML references (like <publication>p-101</publication>)
are mapped to Java object references (in List<Publication> publications).

JAXB collection mapping

I'm new in dealing with XML in Java, but one of services I use returns it as result. Until now, I've dealt with mapping XML into POJO, using #XmlRootElement-like annotations. But now I have absolutely no idea to do with this document:
<?xml version="1.0" encoding="windows-1251"?>
<response>
<status>
<code>0</code>
</status>
<result>
<limit>2</limit>
...
<data>
<row0>
<ID>85427</ID>
<name>Default</name>
<siteID>40628</siteID>
... some elements
</row0>
</data>
</result>
</response>
Until now, I used these classes to bind XML (except 'data' node) into POJO:
#XmlRootElement(name="response")
public class Response {
private Status status;
private String result;
public Status getStatus() {
return status;
}
#XmlElement(name = "status")
public void setStatus(Status status) {
this.status = status;
}
public String getResult() {
return result;
}
#XmlElement(name ="result")
public void setResult(String result) {
this.result = result;
}
}
#XmlRootElement(name = "status")
public class Status {
private String ID;
private String code;
private String error;
public String getID() {
return ID;
}
#XmlElement(name = "ID")
public void setID(String ID) {
this.ID = ID;
}
public String getCode() {
return code;
}
#XmlElement(name = "code")
public void setCode(String code) {
this.code = code;
}
public String getError() {
return error;
}
#XmlElement(name = "error")
public void setError(String error) {
this.error = error;
}
}
But now I need to bind content as collection of elements. I've looked for examples, and everywhere people use specific tag to define root element for collection's item, but in this document, root tags will be as <row0>, <row1> etc.
I use Jackson, which, if I understand correctly, uses JAXB annotations to define XML to POJO bind rules. So could this deal be solved this way, or I have to manipulate this document in DOM-style?
You can solve your problem by using something like this :
Create your Row class that represents your <row0>,<row1> etc... and map it with JAXB like you would do it normally.
Then create a class that extends XmlAdapter<List<Row>,List<Element>> and define the abstracts methods marshall and unmarshall.
Here is some Javadoc to help you :
XmlAdapter : http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/adapters/XmlAdapter.html
Element : http://docs.oracle.com/javase/1.5.0/docs/api/org/w3c/dom/Element.html
Then create a Data class :
public class Data{
private List<Row> rows;
public List<Row> getRows() {
return rows;
}
#XmlAnyElement
#XmlJavaTypeAdapter(MyRowsAdapter.class)
public void setRows(List<Row> result) {
this.rows = rows;
}
}
Then you can add this mapping to your Response class :
private Data data;
public Data getData() {
return data;
}
#XmlElement(name="data")
public void setData(Data data) {
this.data = data;
}
Note that for this solution to work, your <data> element must only contains elements like your Row.
Also, you cannot use #XmlElementWrapper instead of using a Data class because of a bug in JAXB which make incompatible #XmlElementWrapper and #XmlJavaTypeAdapter : https://java.net/jira/browse/JAXB-787

Spring RestTemplate + map XML result to Domain object

With the use of Spring RestTemplate, how can map following XML result to some Domain Object?
As a solution I have designed following Domain classes but I am wonder whether how can I map those contain values (ex: 100, 200, 300) to domain object property.
Thanks.
XML result
<counting>
<value id="1" name="Robin" date="2015-09-03">100</value>
<value id="2" name="Joy" date="2015-09-03">200</value>
<value id="3" name="Tan" date="2015-09-03">300</value>
<counting>
Domain Class
#XmlRootElement(name = "counting")
public class Count {
private Value value;
public Count() {}
// Getters and setters
}
#XmlRootElement(name = "value")
public class Value {
public Value() {}
private long id;
private String name;
private Date date;
// Getters and setters
}
I have solved the issue with following data model
#XmlRootElement(name = "counting")
public class Count {
private List<Value> value;
public Count() {}
// Getters and setters
#XmlElement
public List<Value> getValue() {
return value;
}
public void setValue(List<Value> value) {
return this.value = value;
}
}
#XmlAccessorType(XmlAccessorType.FIELD)
public class Value {
public Value() {}
#XmlAttribute
private long id;
#XmlAttribute
private String name;
#XmlAttribute
private String date;
#XmlValue
private String xmlValue;
// Getters and setters
}

JAXB unmarshal mystery XML

I am using JAXB to unmarshal an XML file.
All I know about the XML file is that it is valid XML.
How then am I supposed to specify a class and/or package to newInstance?
JAXBContext jaxbContext = JAXBContext.newInstance(??????);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object o = (Object) unmarshaller.unmarshal(myFile);
I did not see anything in the docs that address this issue.
You need to tell JaxB what class to unmarshall to so that it can use the annotations in the class to resolve the hierarchy of the xml. You will need to have a class that is also annotated with something like #XmlRootElement. If you want to parse arbitrary xml you will probably need to do something with a DocumentBuilder or xpath.
See this artical for more info.
http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
I have used something like this to convert arbitrary xml to a class. The any field will actually be a list of org.w3c.dom.Element in which you can get information from.
http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Element.html
#XmlRootElement
class Wrapper {
/**
* Everything else
*/
#Transient
#XmlAnyElement(lax = true)
private List<Element> any;
public List<Element> getAny() {
return any;
}
}
In newInstance you must add the class root element that map your xml... below an example
Here an example ..
public static void main(String[] args) throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(Vehicals.class);
final Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final Vehicals vehicals = new Vehicals();
List<Car> cars = new ArrayList<Car>();
Car c = new Car();
c.setName("Mercedes");
cars.add(c);
c = new Car();
c.setName("BMW");
cars.add(c);
vehicals.setCar(cars);
m.marshal(vehicals, System.out);
}
Vehicals.java
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Vehicals {
private List<Car> Car;
public List<Car> getCar() {
return Car;
}
public void setCar(List<Car> cars) {
this.Car = cars;
}
}
Car.java
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement
public class Car {
#XmlTransient
private Long id;
private String name;
#XmlTransient
private String code;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
output.xml
<Vehicle>
<Car>
<name>Mercedes</name>
</Car>
<Car>
<name>BMW</name>
</Car>
</Vehicle>
For the Unmarshal is the same thing. In my case i added Vehicals as parameter in newInstance method.

How do I read attributes using jaxb?

Given this XML:
<response>
<detail Id="123" Length="10" Width="20" Height="30" />
</response>
This is what I have now, but it is not working (I'm getting empty result):
#XmlRootElement(name="response")
public class MyResponse {
List<ResponseDetail> response;
//+getters +setters +constructor
}
public class MyResponseDetail {
Integer Id;
Integer Length;
Integer Width;
Integer Height;
//+getters +setters
}
I'm making a call to a remote service using RestOperations and I want to parse the <detail ..> element. I've tried passing both MyResponse and MyResponseDetail classes to RestOperations but the result is always empty.
What should my object structure look like to match that XML?
You need to annotate your classes like that:
#XmlRootElement
public class Response {
private List<Detail> detail;
public void setDetail(List<Detail> detail) {
this.detail = detail;
}
public List<Detail> getDetail() {
return detail;
}
}
public class Detail {
private String id;
/* add other attributes here */
#XmlAttribute(name = "Id")
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}

Categories

Resources