问题
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?
回答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.
来源:https://stackoverflow.com/questions/26618647/jaxb2-type-restriction-not-working