Skip to main content

Inheritance in jaxb2

12 replies [Last post]
gruenewa
Offline
Joined: 2004-06-30

Hi Jaxb-Experts,

i am testing jaxb2 and found it very useful, but i am wondering on the behaviour of jaxb2 when serializing an inheritance relationship. In my case I have three classes:

//---------------------------

@XmlType
public abstract class Property {
private String description;
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description;}
}

//---------------------------

@XmlType
public class IntegerProperty extends Property {
private int value;
public int getValue() { return value;}
public void setValue(int value) { this.value=value;}
}

//-------------------------------

import java.util.*;

@XmlRootElement
public class PropertyList {

private List properties = new ArrayList();
public void setProperties(List properties) { this.properties = properties;}
public List getProperties() { return properties; }
}

//-------------------------------

My problem is the following: When I create an instance of 'PropertyList', add several 'IntegerProperty' instances to it's properties-List and write it to a XML file, the XML file does NOT contain the integer values, ... only the description which where inherited from the superclass 'Property'. I would expect, that the integer values where also written to XML.

Best regards,
Alexander

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
sekhar
Offline
Joined: 2003-06-25

This should work as you expected. It does in my version of the JAXB 2.0 RI. For e.g. you should see something like:

Sony TV
10

The xsi:type is to be expected since the instance being added is a subtype of the static type.

gruenewa
Offline
Joined: 2004-06-30

Hello,

thank you for your time.
I am using the JAXB_RI_20051123.jar version.
My test driver is coded as follows:
----------------------------------
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

public class TestDriver {
public static void main(String[] args) throws Exception {

PropertyList pList = createPropertyList();

JAXBContext context = JAXBContext.newInstance(PropertyList.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(pList, System.out);
}

private static PropertyList createPropertyList() {
PropertyList list = new PropertyList();

IntegerProperty p = new IntegerProperty();
p.setDescription("Sony TV");
p.setValue(10);

list.getProperties().add(p);

return list;
}
}
-----------------------------------

and it produces the following output:

-----------------------------------

Sony TV
-----------------------------------

So i am missing the xsi:type information and the tag.
All other classes 'PropertyList', 'Property' and 'IntegerProperty' are exactly
coded as listet in my previous post. Did you have any idea, what could be the reason
for this? Thanks.

Best Regards,
Alexander

Message was edited by: gruenewa

sekhar
Offline
Joined: 2003-06-25

Change the line:
JAXBContext context = JAXBContext.newInstance(PropertyList.class);

to

JAXBContext context = JAXBContext.newInstance(PropertyList.class, IntegerProperty.class, Property.class);

It is not always necessary to specify all the classes that are mapped in the JAXBContext.newInstance(..) call. JAXB 2.0 will compute a reference closure on the classes specified. (see javadoc for javax.xml.bind.JAXBContext.newInstance(..) for more information). In this case, since a parameterized list is used as the type of the property, I am not certain that this will work. We will look into this further. In the meantime, please try the above and let us know if it works.

gruenewa
Offline
Joined: 2004-06-30

Thank you. It works now as expected!

Best Regards,
Alexander

bsimonssays
Offline
Joined: 2005-03-09

I'm having a related problem. When I unmarshal a file that contains a type-substituted element, I only get the values from the parent element. However, if I create the JAXBContext using the extended class, the unmarshalling occurs correctly.

My problem is that I won't always know "a priori" what the extended type's class (or package) will be so I can't properly create a JAXBContext to handle it correctly. Is there a way to create a JAXBContext that will try to locate classes on the classpath that correspond to types that it encounters but isn't yet aware of?

I've been looking into various ways of identifying all classes on the classpath and identifying ones created by JAXB through their annotations... but so far a solution has eluded me.

Thanks,

Bill

kohsuke
Offline
Joined: 2003-06-09

Sorry, but all the classes involved in the processing has to be known in advance, so that we can examine them and prepare them accordingly.

If you need a mechanism to build a JAXBContext dynamically, you can build your own mechanism on top of JAXB to do it. For example, you can use service discovery to look for all instances of ClassLocator from all your modules:

[code]
interface ClassLocator {
Class[] locate();
}
[/code]

and put them together in a JAXBContext.

bsimonssays
Offline
Joined: 2005-03-09

Thanks for your prompt response!

In that case, I'll definitely want to build a JAXBContext dynamically. Is ClassLocator a specific interface in JAXB or just an example of how I might define it? Also, I assume by service discovery you mean reflection?

Again, I appreciate your help and I think with just a bit more clarification/guidance I can move forward.

bsimonssays
Offline
Joined: 2005-03-09

Ah! Or did you mean "service discovery" as in the Jakarta commons discovery project?

kohsuke
Offline
Joined: 2003-06-09

The ClassLocater interface is an example of something you'd define. The service discovery can be any mechanism, including Jakarta commons discovery.

For example, if you already have a list of all those "modules" that want to contribute classes, then it's just a matter of defining additional method to list up all the classes.

bsimonssays
Offline
Joined: 2005-03-09

Excellent. Hopefully this can be my last set of questions. How does the ClassLocator identify the list? Can this be done using reflection or will each class name have to be hardcoded by the module's creator? Or do I build some extension into the JAXB source generator that builds a ClassLocator for each package?

The first option would be the most scalable for me but the last option would also be cool if that's possible in JAXB...

bsimonssays
Offline
Joined: 2005-03-09

Hi kohsuke,

I could really use this last piece of guidance. Did you envision the ClassLocator's list being generated during compile time by JAXB, by hand, or dynamically at run time?

Thanks so much for your help.

kohsuke
Offline
Joined: 2003-06-09

Note that you don't have to list the complete list of classes --- JAXB runtime computes transitive reference closure, so most likely you just need to name a few "top level" classes that point to other classes (like the class that represents the root element.)

If those classes were compiled from XJC, you can just give ObjectFactory.class and that will have references to everything else. Or alternatively you can design it to return a package (or package name), and use the version of JAXBContext.newInstance that takes a list of package names.