Reputation: 1101
I'm upgrading a Java object that currently has XML representation in this spirit:
<myObjects>
<myObject uid="42" type="someEnum">
<name>Waldo</name>
<description>yada yada</description>
<myElement>some_string</myElement>
...
</myObject>
...
</myObjects>
myElement is optional - it can be null in Java / omitted in XML.
I'm adding a field that is only relevant if myElement has an actual value
(and to keep compatibility with previous XML, it's optional in itself)
I'm trying to avoid this:
<myElement>some_string</myElement>
<myAttr>foo</myAttr>
and prefer something like this:
<myElement myAttr="foo">some_string</myElement>
but banging my head for 2 days now on how to annotate it.
Upvotes: 2
Views: 400
Reputation: 1101
The answer was dead simple: I'm so used to annotate with XmlElement and XmlAttribute, that I forgot about XmlValue!
The code for MyObject is the same as in Blaise Doughan answer, with one change: myElement is now a class (ElemWithAttr) instead of String:
public class ElemWithAttr {
@XmlValue
public String content;
@XmlAttribute
public String myAttr;
}
Upvotes: 1
Reputation: 148977
You can use the EclipseLink JAXB (MOXy) @XmlPath extension to easily accomplish this:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MyObject {
@XmlAttribute
private int uid;
@XmlAttribute
private String type;
private String name;
private String description;
private String myElement;
@XmlPath("myElement/@myAttr")
private String myAttr;
}
This class will interact with the following XML:
<myObject uid="42" type="someEnum">
<name>Waldo</name>
<description>yada yada</description>
<myElement myAttr="foo">some_string</myElement>
</myObject>
Using the following demo code:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyObject.class);
File file = new File("input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
MyObject myObject = (MyObject) unmarshaller.unmarshal(file);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(myObject, System.out);
}
}
To specify MOXy as your JAXB implementation you need to include a file called jaxb.properties in the same package as your model classes with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
For more information on MOXy's XPath based mapping see:
Upvotes: 3