JAXB2 type restriction not working?
Asked Answered
I

1

3

I have set up a test unit at github. Could someone please check why this is not working though the XML to unmarshal looks good?

https://github.com/jjYBdx4IL/misc-tests/blob/master/src/test/java/jjybdx4il/jaxb/bugs/Stackoverflow26618647Test.java

"<?xml version=\"1.0\" encoding=\"UTF-8\"?><message:GenericData xmlns:message=\"http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message\" xmlns:common=\"http://www.sdmx.org/resources/sdmxml/schemas/v2_1/common\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:generic=\"http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic\" xsi:schemaLocation=\"http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message https://sdw-wsrest.ecb.europa.eu/vocabulary/sdmx/2_1/SDMXMessage.xsd http://www.sdmx.org/resources/sdmxml/schemas/v2_1/common https://sdw-wsrest.ecb.europa.eu/vocabulary/sdmx/2_1/SDMXCommon.xsd http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic https://sdw-wsrest.ecb.europa.eu/vocabulary/sdmx/2_1/SDMXDataGeneric.xsd\">\n"
            + "<message:Header>\n" ...

The most outer element GenericDataType gets instantiated correctly. I checked that using the debugger and setting a breakpoint into a hand-crafted public constructor. However, the message:Header element leads to instantiation of BaseHeaderType class which is abstract.

In SDMXMessage.xsd there is clearly stated that the GenericDataType's header is restricted to GenericDataHeaderType:

<xs:complexType name="GenericDataType">
    <xs:annotation>
        <xs:documentation>GenericDataType defines the contents of a generic data message.</xs:documentation>
    </xs:annotation>
    <xs:complexContent>
        <xs:restriction base="MessageType">
            <xs:sequence>
                <xs:element name="Header" type="GenericDataHeaderType"/>
                <xs:element name="DataSet" type="data:DataSetType" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="footer:Footer" minOccurs="0"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType>

Why does xjc ignore that during code generation?

public abstract class MessageType {

@XmlElement(name = "Header", required = true)
protected BaseHeaderType header;
@XmlAnyElement(lax = true)
protected List<Object> any;
@XmlElement(name = "Footer", namespace = "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message/footer")
protected FooterType footer;

public class GenericDataType
    extends MessageType {
}

Is there anything I can do about that? Any automatic alternative for creating a Java domain model from XSD files that is actually working?

Intestinal answered 28/10, 2014 at 21:17 Comment(5)
Does your log say something? Normally you should get hints on what is wrong. any is typically a catch-all-property which appears when schema construct is too weird for XJC. In your case you might have naming collisions. Check your MessageType if there's a header or a footer element etc. and try to customize that.Wellfavored
I think it has to do with xjc not handling type restrictions.Intestinal
Hard to say without seeing the schema.Wellfavored
OK. Yes, you're probably right about restrictions. And I don't think it is fixable. Consider writing your own class for GenericDataType and customize with <jaxb:class ref="...MyClass"/>.Wellfavored
I've got 1MB of xsds that are constructed that way. Isn't it feasible to write a xjc plugin that handles the type restrictions?Intestinal
W
1

Ok, I'll post this as an answer.

You run into this problem because of this type of the construct:

<xs:complexType name="MessageType" abstract="true">
    <xs:annotation>
        <xs:documentation>MessageType is an abstract type which is used by all of the messages, to allow inheritance of common features. Every message consists of a mandatory header, followed by optional payload (which may occur multiple times), and finally an optional footer section for conveying error, warning, and informational messages.</xs:documentation>
    </xs:annotation>
    <xs:sequence>
        <xs:element name="Header" type="BaseHeaderType"/>
        <xs:any namespace="##targetNamespace" minOccurs="0" maxOccurs="unbounded"/>
        <xs:element ref="footer:Footer" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>   

...

<xs:complexType name="GenericDataType">
    <xs:annotation>
        <xs:documentation>GenericDataType defines the contents of a generic data message.</xs:documentation>
    </xs:annotation>
    <xs:complexContent>
        <xs:restriction base="MessageType">
            <xs:sequence>
                <xs:element name="Header" type="GenericDataHeaderType"/>
                <xs:element name="DataSet" type="data:DataSetType" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element ref="footer:Footer" minOccurs="0"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType>

One element is restricted to a more specific element/type (DataSet). Since all the properties are already defined on the super classe, XJC does not generate them on the "inheriting class"

To my knowledge, there is a number of issues reported on restrictions in JAXB RI. Derivation by restriction seems to be a hard concept for JAXB.

For instance, in this case - how do you think GenericDataType should look like? You basically need to override the header property to use a more specific type. Since XJC places annotations on fields rather than getters/setter, I wonder how you could override such a property. You can add another header property to handle your header, but override?

Try writing such a class - manually and use jaxb:class/@ref-binding. If you make it work, this would give an idea of what should be generated.

Next, if it is feasible via an XJC plugin or not.

The issue you report here is actually XJC's core business. If something don't work there then the "good" thing would be to report (or find an already reported issue) and fix the problem in XJC.

XJC plugins can do really a lot of things. You can completely restructure the model and customize the generation. With the appropriate effort, everything is possible.

But in this case this might be a risky endeavour. Writing advanced XJC plugins is not easy.

If you have a good concept on what exactly the plugin should do and how this particular issue could be fixed in the schema-derived classes, post your thoughts, maybe we'll be able to provide some guidance. Me personally, I've probably written more XJC plugins than anyone else.

I hope this helps.

Wellfavored answered 29/10, 2014 at 6:11 Comment(2)
Why is it necessary to convert the restriction base property into a parent relation? Why not simply flatten it out and define GenericDataType without using parent classes and using class hierarchies at all? The xsd restriction base property looks like a short-cut to allow for easy writing of xsds... is there any purpose beyond that?Intestinal
@Intestinal May be you're right. May be this will work out with flattening. But this may also break the inheritance, I am not sure. Therefore the proposal to map to hand-written classes (jaxb:class/@ref) to figure out how a working set of Java classes should look like. Then it will be possible to say if this is feasible with the plugin or not. You may be right, your approach seems reasonable at the moment. Just be careful not to invest too much time in the plugin beforehand.Wellfavored

© 2022 - 2024 — McMap. All rights reserved.