JAXB Unmarshaller tries to instantiate abstract class ignoring xsi:type if nillable="true" · Issue #890 · javaee/jaxb-v2 (original) (raw)

The problem that JAXB tries to instantiate an abstract class (leading to a InstantiationException) ignoring the concrete type provided with xsi:type is well known since 2006 (or earlier), see "Why doesn't JAXB find my subclass?"
http://weblogs.java.net/blog/kohsuke/archive/2006/04/why_doesnt_jaxb.html

In
http://stackoverflow.com/questions/9157484/jaxb-unmarshaller-tries-to-instantiate-abstract-class-ignoring-xsitype
a detailled example for the industry standard BiPRO is given. We use this very important insurance standard, too.

Its reported that this problem no longer exists in JDK 1.7. But this does not help us, we are tied to a JDK 1.5 by our application server.

The problem was addressed in bug #620, partially solved and the bug was closed.

But the problem still exists if in the XSD nillable="true" is set.

In com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty.buildChildElementUnmarshallers() you can find the following:
// LeafPropertyXsiLoader doesn't work well with nillable elements
if (improvedXsiTypeHandling && !nillable)
...

By the way the property
JAXBRIContext.IMPROVED_XSI_TYPE_HANDLING = "com.sun.xml.bind.improvedXsiTypeHandling" (mentioned in #620)
is not taken into account in com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.setProperty().
This leads to a PropertyException if you configure this property via org.springframework.oxm.jaxb.Jaxb2Marshaller.setUnmarshallerProperties()

We use com.sun.xml.bind:jaxb-impl:2.2.5 and javax.xml.bind:jaxb-api:2.2.6.

Reading the comment "LeafPropertyXsiLoader doesn't work well with nillable elements" I suspect that this problem is not considered as relevant.
But it is definitely an important problem. The attribute nillable="true" is a standard XSD feature not forbidden (believe me I really hate this feature because the generated JAXB classes blow up with all this JAXBElement<> stuff) and JAXB should be able to deal with it correctly.

If you are not convinced of the relevance, think about the following: if you want to define an industry standard (for example insurance as BiPRO does)
with a data model defined by XSDs you certainly will define sequences containing elements of abstract types to allow for an extension to special classes of business or even companies. An element of concrete type has to be provided via xsi:type, but if JAXB does not understand it this concept fails.

Please fix this bug. Otherwise we might be forced to use an ugly message oriented processing with XPATH instead of a beautiful object oriented processing with JAXB.

As long as the bug is not fixed: is a work around available via globalBindings ?

Sample:

Sequence containing element of abstract type[xmlns:tar="http://www.bipro.net/namespace/tarifierung"\]:
<xsd:complexType name="CT_VersicherungssummeOderLeistung">
xsd:complexContent
<xsd:extension base="allgemein:CT_Objekt">
xsd:sequence
<xsd:element name="ArtID" type="daten:STE_VersicherungssummeOderLeistung"
minOccurs="0" maxOccurs="1" nillable="true" />
...



Abstract type[xmlns:daten="http://www.bipro.net/namespace/datentypen"\]:
<xsd:complexType name="STE_VersicherungssummeOderLeistung" abstract="true">
xsd:simpleContent
<xsd:extension base="xsd:string" />

Concrete type[xmlns:daten="http://www.bipro.net/namespace/datentypen"\]:
<xsd:complexType name="STE_VersicherungssummeOderLeistungBasis"
final="#all">
xsd:simpleContent
<xsd:restriction base="daten:STE_VersicherungssummeOderLeistung">
...
<xsd:enumeration value="Krankentagegeld">
xsd:annotation
xsd:documentationKrankentagegeld


...


XML-Request:
...
tar:VersicherungssummeOderLeistung
<tar:ArtID xsi:type="daten:STE_VersicherungssummeOderLeistungBasis" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Krankentagegeld
...

...

leads to
INFO: failed to create a new instance of class net.bipro.namespace.datentypen.STEVersicherungssummeOderLeistung
java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30)
at java.lang.reflect.Constructor.newInstance(Constructor.java:501)
at com.sun.xml.bind.v2.ClassFactory.create0(ClassFactory.java:133)
...

On the other hand marshalling leads to non valid XML omitting xsi:type declaration:
tar:ArtIDKrankentagegeld
if one uses the generated method in the ObjectFactory:
public JAXBElement createCTVersicherungssummeOderLeistungArtID(STEVersicherungssummeOderLeistung value)

{ return new JAXBElement(_CTDynamikArtID_QNAME, STEVersicherungssummeOderLeistung.class, CTVersicherungssummeOderLeistung.class, value); }

This would be correct:
<tar:ArtID xsi:type="daten:STE_VersicherungssummeOderLeistungBasis" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Krankentagegeld

Affected Versions

[2.2.5]