Below I'll demonstrate how an XmlAdapter
could be used to support both marshalling and unmarshalling for this use case.
XmlAdapter (IncludeFruitAdapter)
An XmlAdapter
could be used for this use case.
import java.io.File;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class IncludeFruitAdapter extends XmlAdapter<IncludeFruitAdapter.Include, Fruit> {
private JAXBContext jc;
private String href = "fruit.xml";
public IncludeFruitAdapter() {
try {
jc = JAXBContext.newInstance(Fruit.class);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static class Include {
@XmlAttribute
public String href;
@XmlElement(namespace="http://www.w3.org/2001/XInclude")
public Fallback fallback;
}
public static class Fallback {
@XmlElementRef
public Fruit value;
}
@Override
public Include marshal(Fruit fruit) throws Exception {
File xml = new File(href);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(fruit, xml);
Include include = new Include();
include.href = href;
include.fallback = new Fallback();
include.fallback.value = new Fruit();
return include;
}
@Override
public Fruit unmarshal(Include include) throws Exception {
File xml = new File(include.href);
Unmarshaller unmarshaller = jc.createUnmarshaller();
try {
return (Fruit) unmarshaller.unmarshal(xml);
} catch(Exception e) {
return include.fallback.value;
}
}
}
Tree
The @XmlJavaTypeAdapter
is used to reference the XmlAdapter
.
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tree {
@XmlJavaTypeAdapter(IncludeFruitAdapter.class)
@XmlElement(name="include", namespace="http://www.w3.org/2001/XInclude")
private Fruit fruit;
}
Fruit
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {
private String name;
}
Demo
Below is some demo code you can run to prove that everything works:
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Tree.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Tree tree = (Tree) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(tree, System.out);
}
}