Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB, abstract classes, and multi-module projects

Tags:

java

jaxb

Let's say I have a JAR xxx-core.jar with the following classes:

@XmlRootElement
@XmlSeeAlso({Imp1.class, Imp2.class})
public abstract class Abst {...}

@XmlRootElement
public class Imp1 extends Abst {...}

@XmlRootElement
public class Imp2 extends Abst {...}

public class Main {
  @XmlElement
  private Abst abst;

  public static void load(File file) {
    // unmarshal this
  }
  public void save(File file) {
    // marshal this
  }
}

So far, so good. Main can be marshalled and unmarshalled, and the correct implementation of Abst is used.

Now, what happens when somebody else comes along and creates another project xxx-extension.jar that uses xxx-core.jar, but contains the following class:

@XmlRootElement
public class ExtensionImp extends Abst {...}

and assigns an instance of this new implementation to Main's member variable? Since it's not explicitly given in the XmlSeeAlso annotation, how can I make sure that ExtensionImp will be correctly marshalled/unmarshalled? (I've played with the class list in JAXBContext.newInstance(), but that doesn't seem to solve the problem.)

like image 314
Kricket Avatar asked Aug 10 '26 20:08

Kricket


1 Answers

The @XmlSeeAlso annotation is just a mechanism that lets your JAXB (JSR-222) impl know to look at other classes. Alternatively you could just include then in the classes used to bootstrap the JAXBContext. When you create your JAXBContext you just need to do:

JAXBContext jc = JAXBContext.newInstance(Abst.class, ExtensionImp.class);

UPDATE 1

I've played with the class list in JAXBContext.newInstance(), but that doesn't seem to solve the problem.

This should definitely solve the problem, what happens when you do this.


UPDATE 2

I suspect your issue is due to the document you are unmarshalling and not how you are bootstrapping. The following should help.

Inheritance - xsi:type

With the way that you currently have your mappings, you need to ensure that your XML looks like the following to have an instance of Imp2 instantiated and populated into the abst field on the Main class.

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

For more info see:

  • http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html

Inheritance Substitution Groups

If you would rather unmarshal an XML document like the following:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<main>
    <imp2/>
</main>

Then you need to leverage the @XmlElementRef annotation.

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Main {
    @XmlElementRef
    Abst abst;
}

For more info see:

  • http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
like image 130
bdoughan Avatar answered Aug 12 '26 12:08

bdoughan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!