TheArchitect
TheArchitect

Reputation: 129

Unmarshalling inheritance structure with JAXB

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

Answers (1)

bdoughan
bdoughan

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

Related Questions