I am getting XML from a REST service that looks like:
<entity>
<foo>
<count>1</count>
<date>1970-01-01</date>
<margin>78.67</margin>
</foo>
<bar>
<count>2</count>
<date>1450-09-17</date>
<margin>24.56</margin>
</bar>
<baz>
<count>11</count>
<date>1968-11-12</date>
<margin>98.76</margin>
</baz>
</entity>
And I'm parsing with a class Entity.java that has:
@XmlRootElement(name = "entity")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entity implements Serializable {
@XmlElements({
@XmlElement(name="foo"),
@XmlElement(name="bar"),
@XmlElement(name="baz")
})
private List<EntityElement> entityElements;
....
With an EntityElement class like:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class EntityElement implements Serializable {
@XmlElement(required = true)
private int count
@XmlElement(required = true)
private String date;
@XmlElement(required = false)
private long margin;
....
This all works exactly like I expect and I get a list of EntityElements. What I would like to do is add a name field and have it populated with the name of the element that was found (a foo, bar, or baz) but I'm not seeing any way to do this. Any help or suggestions would be appreciated.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
You could use the @XmlVariableNode
that we added to MOXy in EclipseLink 2.5.1 for this use case.
Entity
We will use MOXy's @XmlVariableNode
on the entityElements
field. On the field we specify the field on the target class that represents the element name.
import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVariableNode;
@XmlRootElement(name = "entity")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entity implements Serializable {
@XmlVariableNode("name")
private List<EntityElement> entityElements;
}
EntityElement
We will use the @XmlTransient
annotation to prevent the value of the name
field from being marshalled as a child element.
import java.io.Serializable;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class EntityElement implements Serializable {
@XmlTransient
private String name;
@XmlElement(required = true)
private int count;
@XmlElement(required = true)
private String date;
@XmlElement(required = false)
private long margin;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties
in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
Since MOXy is a JAXB (JSR-222) implementation only the standard runtime APIs are required.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Entity.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum19194567/input.xml");
Entity entity = (Entity) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(entity, System.out);
}
}
input.xml/Output
This is the XML document from your question.
<?xml version="1.0" encoding="UTF-8"?>
<entity>
<foo>
<count>1</count>
<date>1970-01-01</date>
<margin>0</margin>
</foo>
<bar>
<count>2</count>
<date>1450-09-17</date>
<margin>0</margin>
</bar>
<baz>
<count>11</count>
<date>1968-11-12</date>
<margin>0</margin>
</baz>
</entity>