3

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.)

2 Answers 2

1

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:

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:

Sign up to request clarification or add additional context in comments.

2 Comments

(note: I don't actually have 2 projects yet; this question was more forward-thinking...) I commented out the XmlSeeAlso on the Abstract class, and added the two sub-classes as arguments to newInstance(). I get an UnmarshalException: unable to create instance of Abst - with linked exception [java.lang.InstantiationException]. I should also note that in my particular case, the member is actually a List<Abst> annotated with XmlElementWrapper (tried with XmlElement also). (I tried a test where I just put a single instance instead of the list, but with the same result.)
@KelseyRider - I have updated my answer again. I suspect the document you are trying to unmarshal does not match your mappings. Also try marshalling your model to XML to see if it matches the input you are using.
0

I solved similar problem using @XmlAnyElement(lax=true). Try to put this annotation instead of @XmlElement into main class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.