Reputation: 129
I want to unmarshall the following XML structure using JAXB:
<orCondition>
<andCondition>
<andCondition>
<simpleCondition value="val1" />
<simpleCondition value="val2" />
</andCondition>
<simpleCondition value="val3" />
</andCondition>
<simpleCondition value="val4" />
</orCondition>
I have the following Java classes:
Condition base class
@XmlType(name="condition")
public class Condition {
}
Composite class containing two conditions
@XmlType(name="composite")
public class Composite extends Condition {
@XmlElement(name = "condition", type = Condition.class)
private Condition firstCondition;
@XmlElement(name = "condition", type = Condition.class)
private Condition secondCondition;
public Condition getFirstCondition() {
return firstCondition;
}
public void setFirstCondition(Condition firstCondition) {
this.firstCondition = firstCondition;
}
public Condition getSecondCondition() {
return secondCondition;
}
public void setSecondCondition(Condition secondCondition) {
this.secondCondition = secondCondition;
}
}
And condition
@XmlType(name = "andCondition")
public class And extends Composite {
}
Or condition
@XmlType(name = "orCondition")
public class Or extends Composite {
}
Simple leaf class condition
@XmlType(name = "simpleCondition")
public class Simple extends Condition {
@XmlAttribute
String value;
}
This does not work. I have an instance variable in an other class that looks like this:
@XmlElement(name = "condition", type = Condition.class)
private Condition condition;
It stays null after unmarshalling. The rest of the object unmarshalls fine
Anny suggestions? Or is this not possible?
Upvotes: 1
Views: 4174
Reputation: 149047
You could structure your model like:
Composite
You could change your Composite
class to look something like the following and use the @XmlElementRef
annotation. @XmlElementRef
corresponds to the XML schema concept of substitution groups:
package forum9006785;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class Composite extends Condition {
@XmlElementRef
private Condition[] condition = new Condition[2];
public Condition getFirstCondition() {
return condition[0];
}
public void setFirstCondition(Condition firstCondition) {
condition[0] = firstCondition;
}
public Condition getSecondCondition() {
return condition[1];
}
public void setSecondCondition(Condition secondCondition) {
condition[1] = secondCondition;
}
}
Condition
package forum9006785;
public class Condition {
}
And
For each of the subclasses that can appear in the XML you will need to annotate with @XmlRootElement
. This acts as the type identifier for the @XmlElementRef
property.
package forum9006785;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "andCondition")
public class And extends Composite {
}
Or
package forum9006785;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "orCondition")
public class Or extends Composite {
}
Simple
package forum9006785;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "simpleCondition")
public class Simple extends Condition {
@XmlAttribute
String value;
}
Demo
package forum9006785;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(And.class, Or.class, Simple.class);
File xml = new File("src/forum9006785/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Condition condition = (Condition) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(condition, System.out);
}
}
Input/Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<orCondition>
<andCondition>
<andCondition>
<simpleCondition value="val1"/>
<simpleCondition value="val2"/>
</andCondition>
<simpleCondition value="val3"/>
</andCondition>
<simpleCondition value="val4"/>
</orCondition>
For More Information
Upvotes: 1