I'm working with a set of schema descriptor files written by a third party. I need to generate JAXB stubs for them. Each XSD defines a different message type, along with a number of supporting simple and complex types. Many of the types are common to each XSD, but rather than factor them out into a separate XSD, the authors chose to define them in each namespace. This creates a grundle of namespace collisions when I try to compile the XSD's using xjc into a single package. I'm forced to separate them into unique packages. The problem is that this makes them non-interchangeable, when they should be. I have to do a lot of extra conversion to use data from one message type in a different message type.
My question: is there some way (binding customization?) I can instruct xjc to use one java class for each shared type, rather than unique classes spread across different packages?
Here's a simplified example. I've got two XSD's, one for an insert message and another for a response message. The response is meant to reference an insert message.
<!-- insert.xsd -->
<xs:schema
xmlns="msg.insert"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="msg.insert">
<xs:element name="Message" type="Message" />
<xs:complexType name="Message">
<xs:sequence>
<xs:element
maxOccurs="1"
minOccurs="1"
name="MessageId"
type="Identifier" />
<xs:element
maxOccurs="1"
minOccurs="1"
name="SequenceId"
type="Identifier" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Identifier">
<xs:sequence>
<xs:element
maxOccurs="1"
minOccurs="1"
name="ID"
type="xs:string" />
<xs:element
maxOccurs="1"
minOccurs="1"
name="Created"
type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Here's the second XSD...
<!-- response.xsd -->
<xs:schema
xmlns="msg.response"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="msg.response">
<xs:element name="Message" type="Message" />
<xs:complexType name="Message">
<xs:sequence>
<xs:element
maxOccurs="1"
minOccurs="1"
name="MessageId"
type="Identifier" />
<xs:element
maxOccurs="1"
minOccurs="1"
name="SequenceId"
type="Identifier" />
<xs:element
maxOccurs="1"
minOccurs="1"
name="ReferenceId"
type="Identifier" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Identifier">
<xs:sequence>
<xs:element
maxOccurs="1"
minOccurs="1"
name="ID"
type="xs:string" />
<xs:element
maxOccurs="1"
minOccurs="1"
name="Created"
type="xs:dateTime" />
</xs:sequence>
</xs:complexType>
Note the Identifier complex type is identical in both schemas. It can and should be interchangeable between message types. But when I run xjc thus...
xjc -d java -p example.msg insert.xsd response.xsd
...I get collisions on the Message, Identifier, and ObjectFactory classes as follows.
[ERROR] A class/interface with the same name "example.msg.Message" is already in use. Use a class customization to resolve this conflict.
line 8 of insert.xsd
[ERROR] (Relevant to above error) another "Message" is generated from here.
line 8 of response.xsd
[ERROR] A class/interface with the same name "example.msg.Identifier" is already in use. Use a class customization to resolve this conflict.
line 15 of insert.xsd
[ERROR] (Relevant to above error) another "Identifier" is generated from here.
line 16 of response.xsd
[ERROR] Two declarations cause a collision in the ObjectFactory class.
line 8 of insert.xsd
[ERROR] (Related to above error) This is the other declaration.
line 8 of response.xsd
I completely understand why xjc is complaining, I'm trying to find a way to coax xjc into using a common class for the Identifier type, as well as resolve the collisions in the ObjectFactory class. One solution would be to factor the common types out into a separate namespace and reference them from each message type's XSD, but as mentioned these are all written by a third party and I don't have the ability to change them.
For now I'm compiling each XSD into a separate java package. This works but is very, very cumbersome.
The error output suggests there's a way to do this with a binding customization, but so far I haven't figured out how to make that work. Can anyone point me in the right direction?
you can solve this problem just by adding the following custom arg in the wsimport command:
-B-XautoNameResolution (without spaces)
This way, any name conflict will be automatically removed when parsing the xml.
Hope this helps
I had to deal with a similar issue to compile a huge library of XSD ( >1.8K XSD files) with a large rate of duplicated types between the XSDs.
The only feasible solution I've found was to generate an intermediate model with default packages per namespace, and process that afterward with Java codemodel moving all type classes into a single package, collapsing the duplicated classes.
Finally, I had to hack the marshaling to avoid namespace aware in the collapsed classes.
It seems like a crazy solution but worked just fine.
BTW -XautoNameResolution is just a way to automatically rename the duplicated type classes, but it does not solve the duplication issue.
Related
Using java 1.8, maven-jaxb2-plugin:0.14.0, and JAXB 2.3.0
when I generate java classes from XSD files, and some classes are too simple, JAXB decides to skip them. Instead, it puts a #XmlElementWrapper annotation.
Example:
<xs:complexType name="AAAA">
<xs:sequence>
<xs:element name="eeee" type="BBBB" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Turns into
#XmlElementWrapper(namespace = ...)
#XmlElement(namespace = ....)
protected List<BBBB> eeee;
in the logs, I see:
[INFO] Replacing field [eeee AAAA]
In this particular care this optimization does not help me, I would prefer to see the classes as I designed the XSD (eg. AAAA turned into a Java class).
Is there a way to force JAXB into generating all classes and stop running "Replacing field" step?
I'm not sure that I understand correctly. It will be better if you publicate full xsd model and original generated java class/expected class.
But, may be using refernce will help you
<xs:complexType name="AAAA">
<xs:sequence>
<xsd:element ref="eeee" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="eeee">
<xs:sequence>
<xs:element name="eeee" type="BBBB" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
What are the conceptual and technical disadvantages of this request/response structure:
A)
<xs:element name="OrderRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:integer"/>
<xs:element name="OrderType" type="xs:integer"/>
<xsd:element name='OrderAttributes' type='xsd:string'/>
</xs:sequence>
</xs:complexType>
</xs:element>
where OrderAttributes element will contain string in the following XML structure:
<OrderName> xy </OrderName>
<OrderDate> xy </OrderDate>
<OrderDetails> xy </OrderDetails>
....lots of other attributes
compared to this request/response structure
B)
<xs:element name="OrderRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:integer"/>
<xs:element name="OrderType" type="xs:integer"/>
<xsd:element name="OrderAttributes">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderName" type="xs:string"/>
<xs:element name="OrderDate" type="xs:date"/>
<xs:element name="OrderDetails" type="xs:string"/>
....lots of other attributes
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I need to design web service interface for orders processing, and I am thinking about the two alternatives mentioned above.
Version A, is more generic, so interface doesn't need to change, when OrderAttributes structure changes in any way.
But schema validation is not possible.
And my question is, what are other disadvantages compared to version B. I am analyst, not programmer, so I cannot say, if there is some impact on parsing requests, generating code from contract etc...
First note that your generic use of the word attribute to refer to a property can be confusing in XML, where attribute refers to a specific construct that stands apart from element:
<element attribute="attribute value">
<childElement>child element value</childElement>
</element>
Then, while doing design, you might consider which properties you wish to represent as XML attribute and which you wish to represent as XML elements. See XML attribute vs XML element for help deciding.
Regarding your A vs B proposed designs, note that A simply is not viable -- you cannot have unescaped markup within an element declared to have xs:string content as you've shown. Furthermore, A would then require further parsing of the OrderAttributes contents anyway whereas B would leverage the XML parser to process OrderAttributes contents. (And, like you said, B would not leverage XSD validation either.)
For future expansion, consider instead the use of xs:any, which supports various interpretations of wildcard contents via its processContents attribute values of strict, lax, or skip.
I'm going to generate java code from the xsd. I want to know how to remove xsd element when converting xsd to java using jaxb. My goal is to ignore message
Ex:
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:string" name="message"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Java Variables
#XmlElement
protected String name;
In here you can see that message element got removed. I want to know how to do that?
If I understand you correctly, to sum it up you want to ignore a mandatory element and still want the result to validate correctly. My short answer is that this is contradictory and does not make sense. JAXB is built to do it correctly and you want do it wrongly(?).
You have several options, eg.
Live with the extra constructor argument.
Generate no-arg constructor instead.
Don't generate, but hand code JAXB annotated classes. Maybe turn off some validation.
Don't use JAXB, use something else (dom4j et. al.) or handcraft the xml
Possibly you can add some overriding in a binding file or even a plug-in, but I wouldn't think it was worth it.
Can you alter the .xsd ?
The current Element "note" tells that both "name" and "message" are mandatory. If you want "message" to be conditional you probably need to add minOccurs="0" attribute:
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:string" name="message" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
We have the following problem. We try to generate Java code from XSD files that contain group declarations and multiple group references to these group declarations. Here a simplified version:
<xs:group name="Information">
<xs:sequence>
<xs:element name="Name">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="updated" type="xs:boolean"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:group>
<xs:element name="Address">
<xs:complexType>
<xs:sequence>
<xs:group ref="Information" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Customer">
<xs:complexType>
<xs:sequence>
<xs:group ref="Information"/>
</xs:sequence>
</xs:complexType>
</xs:element>
The main points are:
Each of these elements is defined in its own file
The same group Information is references twice
There is no separate type for the group
There is also no separate type for the Name element inside the group
We cannot change the XSD file
The problem we face now is that xjc generates non-deterministically depending on the machine where we build, sometimes the type Address.Name and sometimes the type Customer.Name, because the Name element is a complex type and requires a type.
Is there any way to tell xjc to always generate the same type?
Customize the anonymous complex type with the jaxb:class binding and specify the class name.
Use <jaxb:globalBindings localScoping="toplevel"/> to generate inner classes on the top level instead.
A combination of these two will give you a predictable class.
You could try the -episode command line option of XJC. It is primarily meant for compilation in multiple steps, but I think it basically "dumps decisions" taken by XJC during a compilation into a (binding) configuration file. If you are lucky, you find suitable settings related to the Name element/type in the episode file which you can copy into your binding configuration file to make XJC behave deterministically.
I'm generating an object which has an XSD schema
<xs:element name="roleAssignments" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="roleAssignment" type="tns:roleAssignmentDataObj" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
but which generates Java code as
protected ProjectDataObj.RoleAssignments roleAssignments;
I'm trying to get it generate
protected List<RoleAssignment> roleAssignments;
I've tried fiddling around with xjb binding for wsimport but that hasn't seemed to give me the control I want. Is there a way to do this?
It turns out I needed to use a plug-in to XJC.
I used https://github.com/dmak/jaxb-xew-plugin. This plug-in will correctly generate the correct wrappers on the client side.
Have you tried XJC?
Here is more reference:
http://theopentutorials.com/examples/java/jaxb/generate-java-class-from-xml-schema-using-jaxb-xjc-command/