How can I instruct JAXB to process this ?
XML
<root>
<parent>
<child id="1" name="foo" />
</parent>
<parent>
<child id="3" name="foo2" />
</parent>
<parent>
<child id="4" name="bar2" />
</parent>
<parent>
<child id="2" name="bar" />
</parent>
</root>
Root.java
@XmlRootElement
public class Root {
@XmlElement(name="parent/child")
List<Child> allChildren;
}
This doesn't work ... allChildren is empty.
Unmarshal is the process of binding the XML document using JAXB compiler and generating mapping java classes then constructing the instances with values available in XML document. Marshal is the reverse process of it. First we construct the instances and then write a XML document using the constructed instances.
Unmarshal a root element that is globally declared The JAXBContext instance maintains a mapping of globally declared XML element and type definition names to JAXB mapped classes. The unmarshal method checks if JAXBContext has a mapping from the root element's XML name and/or @xsi:type to a JAXB mapped class.
You could change your model and do the following:
Root
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElement(name="parent")
List<Parent> allParents;
}
Parent
@XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
@XmlElement(name="child")
List<Child> allChildren;
}
UPDATE
Is it possible to avoid the parent class ?
There are a couple of different ways to accomplish this:
OPTION #1 - Any JAXB Implementation using XmlAdapter
You could use an XmlAdapter to virtually add in the Parent
class.
ChildAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ChildAdapter extends XmlAdapter<ChildAdapter.Parent, Child> {
public static class Parent {
public Child child;
}
@Override
public Parent marshal(Child v) throws Exception {
Parent parent = new Parent();
parent.child = v;
return parent;
}
@Override
public Child unmarshal(Parent v) throws Exception {
return v.child;
}
}
Root
The @XmlJavaTypeAdapter
annotation is used to reference the XmlAdapter
.
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElement(name="parent")
@XmlJavaTypeAdapter(ChildAdapter.class)
List<Child> allChildren;
}
Child
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class Child {
@XmlAttribute
int id;
@XmlAttribute
String name;
}
OPTION #2 - Using EclipseLink JAXB (MOXy)
If you are using EclipseLink JAXB (MOXy) as your JAXB (JSR-222) implementation then you could do the following (Note: I'm the MOXy lead):
Root
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
@XmlElement(name="parent")
List<Child> allChildren;
}
Child
MOXy's @XmlPath
annotation works pretty much the way you are trying to use the @XmlElement
annotation in your post.
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlAccessorType(XmlAccessType.FIELD)
public class Child {
@XmlPath("child/@id")
int id;
@XmlPath("child/@name")
String name;
}
For More Information
You will have to create a class representing the <parent>
element, such as
@XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
@XmlElement(name="child")
Child child;
}
You could then create a type adapter
public class ParentToChildAdapter extends XmlAdapter<Parent, Child> {
public Parent marshal(Child c) {
Parent p = new Parent();
p.child = child;
return p;
}
public Child unmarshal(Parent p) {
return p.child;
}
}
and use this on the root class
@XmlRootElement
public class Root {
@XmlElement(name="parent")
@XmlJavaTypeAdapter(ParentToChildAdapter.class)
List<Child> allChildren;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With