Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@XmlSeeAlso alternative

I have the following:

class A{
    @XmlElement
    String name;

    //getters and setters
}

and

class B extends A{
    @XmlElement
    String height;

    //getters and setters
}

finally I have

@XmlRootElement
class P{
    @XmlElement
    List<A> things;

    //getters and setters
}

If I do

List<A> l = new ArrayList<A>();
l.add(new B('hello', 20)) //Add new B with height of 20 and name hello

P p = new P();
p.setThings(l); //Set things to list of B's.

and marshal P, I only get the field as part of things and not height.

I know that I can add @XmlSeeAlso(B.class) in A and it will all work.

But the issue is that I don't know all extended classes other than B, as A may be extended on runtime.

How do I dynamically define @XmlSeeAlso on runtime?

like image 883
Ken Hirakawa Avatar asked Nov 29 '11 21:11

Ken Hirakawa


1 Answers

This depends on how you are creating your JAXBContext. The newInstance method can be called with an explicit list of all your classes, the documentation for that method also gives a similar example.

The client application must supply a list of classes that the new context object needs to recognize. Not only the new context will recognize all the classes specified, but it will also recognize any classes that are directly/indirectly referenced statically from the specified classes. Subclasses of referenced classes nor @XmlTransient referenced classes are not registered with JAXBContext. For example, in the following Java code, if you do newInstance(Foo.class), the newly created JAXBContext will recognize both Foo and Bar, but not Zot or FooBar:

class Foo {
    @XmlTransient FooBar c;
    Bar b;
}
class Bar { int x; }
class Zot extends Bar { int y; }
class FooBar { }

Edit: If you know at least the package names of potential jaxb classes you could also create a context given a context path.

If the above is not possible you could also create the list of classes at runtime, based on the object you want to serialize. I think it would be better to try to refactor your code to make this unnecessary. The code below is untested:

Set<Class> classes = new HashSet<Class>();
classes.add(p.getClass());
for (A a : p.getThings()) {
    classes.add(a.getClass());
}
JAXBContext context = JAXBContext.newInstance(classes.toArray(new Class[classes.size()]));
like image 191
Jörn Horstmann Avatar answered Sep 26 '22 05:09

Jörn Horstmann