queenbee
queenbee

Reputation: 155

JAXB inheritance - non-abstract base class

I'm currently trying to use JaxB but i'm not being very successful with a relatively simple example. My example is the following:

public class A {
   private String m_name;
}

public abstract class B_Base extends A {

}

public class B1 extends B_Base {
   private String m_value1;
}

public class B2 extends B_Base {
   private String m_value2;
}

All my attempts on (even marshalling) have failed. I have looked through Blaise Doughan's blog including articles such as http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html but none of them seem to help on my example. It is certainly possible that i've misapplied his examples. I would seem to me that my example should be something that is easily supported in JaxB - after all, java is largely based on inheritance relationships!

I would be grateful for a fast response!

Upvotes: 2

Views: 2500

Answers (1)

bdoughan
bdoughan

Reputation: 149047

You could do the following:

  • JAXB will pull in super classes, but not subclasses. You can create the JAXBContext on the leaf classes or you can use an @XmlSeeAlso annotation on the parent class to pull in the sub classes.
  • You will need to provide root element information. Below I have done this with a JAXBElement.

Demo

import javax.xml.bind.*;
import javax.xml.namespace.QName;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(B1.class, B2.class);

        B1 b1 = new B1();
        JAXBElement<A> jaxbElement = new JAXBElement<A>(new QName("root"), A.class, b1);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(jaxbElement, System.out);
    }

}

Output

Below is the output from running the demo code:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="b1"/>

UPDATE

hi, probably a really stupid question, but just wondering, how would I adapt this if I have a class C that holds an ArrayList of A objects (or subclasses)?

Java Model

C

Here is the C class as described in your comment:

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class C {

    private List<A> as = new ArrayList<A>();

    @XmlElement(name="a")
    public List<A> getAs() {
        return as;
    }

}

A

Here is how you can leverage the @XmlSeeAlso annotation to bring in the subclasses.

@XmlSeeAlso({ B1.class, B2.class })
public class A {
    private String m_name;
}

Demo Code

Below is some demo code to show everything works. Note now that we use @XmlSeeAlso we use @XmlSeeAlso we don't need to include the subclasses when bootstrapping JAXBContext.

Demo

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(C.class);

        C root = new C();
        root.getAs().add(new B1());
        root.getAs().add(new B2());

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }

}

Output

Below is the output from running the demo code.

<?xml version="1.0" encoding="UTF-8"?>
<c>
    <a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="b1"/>
    <a xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="b2"/>
</c>

Upvotes: 2

Related Questions