Generate enum from deeply nested xsd elements - java

I'm having a problem generating enum from deeply nested xsd elements. When I generate the code during maven build, my enums are of type string. Here's an example.
<xs:element name="Car">
<xs:complexType>
<xs:sequence>
<xs:element name="CarModal">
<xs:complexType>
<xs:sequence>
<xs:element name="Type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="SomeValue"/>
<xs:enumeration value="AnotherValue"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:completType>
</xs:element>
</xs:sequence>
From the above example we would have another 20 elements inside of Car element that contains enum value name 'Type'. I have a binding file to bind 'Type' to jaxb:typesafeEnumClass but it's not working, i'm still getting strings as my enum type. Here's an example of my binding.
<jaxb:bindings schemaLocation="someLocation">
<jaxb:bindings node="//xs:element[#name='Car']>
<jaxb:bindings node="//xs:element[#name='CarModal']">
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
<jaxb:typesafeEnumClass name="Type"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Thanks for any help and I can't change the xsd

I guess your bindings are nor precise enough. When you write //xs:element[#name='CarModal'], you basically say "any CarModal element inside my schema". Next, you say you have many Type elements so xs:element[#name='Type']/xs:simpleType is not precise enough.
Try more precise expressions like
xs:complexType/xs:sequence/xs:element[#name='CarModal']/
xs:complexType/xs:sequence/xs:element[#name='Type']/xs:simpleType
Next, your binding makes a general impression of the incorrect syntax. For instance this:
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
is invalid XML (missing " after xs:simpleType). So it might be the case that you binding is not considered at all - otherwise you should have gotten an error instead of generated code. Double-check if the binding is applied at all.

Related

Most elegant way to make an XSD attribute accept two types (xs:string and xs:long)?

I have received a specification for a SOAP service where the request that I'm sent will contain the following:
<eventContexts>
<eventContext name="eventType" value="Unwind"/>
<eventContext name="referenceId" value="26214"/>
</eventContexts>
I am trying to model this object in the XSD but I'm blocked in the choice of type for the attribute value. As you can see in the above example, it can either be a xs:string (case Unwind) or a xs:long (case 26214).
What type should I choose to make the attribute value accept both xs:string and xs:long?
So far I can think of two things:
1) Should I create two different attributes, e.g. stringValue and longValue:
<xs:complexType name="XmlEventContext">
<xs:attribute name="name" type="xs:string"/>Sh
<xs:attribute name="stringValue" type="xs:string" minOccurs="0"/>
<xs:attribute name="longValue" type="xs:long" minOccurs="0"/>
</xs:complexType>
... and let the client send me the good value in the good attribute? (This looks ugly to me but I'm not a big expert).
2) Should I extend the auto-generated class XmlEventContext with a custom class that takes the value as xs:string and then tries to cast it to xs:long?
public class XmlEventContextComplete extends XmlEventContext {
//code to manage a property referenceId which can either be long or string
}
3) Any other more elegant suggestion?
Thanks in advance!
You want a type that can be either a long or a specific enumerated string.
This should cover that case:
<xs:complexType name="xmlEventContext">
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="value" type="longOrUnwind" />
</xs:complexType>
<xs:simpleType name="longOrUnwind">
<xs:union memberTypes="xs:long unwindConstant" />
</xs:simpleType>
<xs:simpleType name="unwindConstant">
<xs:restriction base="xs:string">
<xs:enumeration value="Unwind" />
</xs:restriction>
</xs:simpleType>

XPath evaluation of results in an empty target node

My wsdl specification contains imported XSD schema.
wsdl file looks like below
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" ....>
<wsdl:types>
<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd2" namespace="http://tempuri.org/"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svcc?xsd=xsd4" namespace="http://schemas.datacontract.org/2004/07/System.Web.Services.Protocols"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd0" namespace="http://schemas.microsoft.com/2003/10/Serialization/"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd1" namespace="http://schemas.datacontract.org/2004/07/ABCUser.Web.Services"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd3" namespace="http://schemas.datacontract.org/2004/07/ABCUser.Web.ServiceModels"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd5" namespace="http://schemas.datacontract.org/2004/07/System"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd6" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd7" namespace="http://schemas.datacontract.org/2004/07/System.Collections.Generic"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd8" namespace="http://schemas.datacontract.org/2004/07/ABC.Fs.UIEntities"/>
<xsd:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd9"/>
</xsd:schema>
</wsdl:types>
.......
</wsdl:definitions>
My jaxb bindings file look like below:
<jaxws:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.1"
wsdlLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?wsdl">
<enableWrapperStyle>true</enableWrapperStyle>
<enableAsyncMapping>false</enableAsyncMapping>
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema/xs:complexType[#name='Node']/xs:sequence/xs:element[#name='Type']">
<jaxb:class name="NodeTypeString"/>
</jaxws:bindings>
</jaxws:bindings>
If I don't use bindings.xml, I get following error while generating java classes through wsimport
[ERROR] Two declarations cause a collision in the ObjectFactory class.
line 1 of https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd3
[ERROR] (Related to above error) This is the other declaration.
line 1 of https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd3
Schema it is complaining about looks like below
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.datacontract.org/2004/07/ABCUser.Web.ServiceModels" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/ABCUser.Web.ServiceModels">
<xs:import schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd6" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
.......
<xs:complexType name="Node">
<xs:sequence>
<xs:element minOccurs="0" name="Description" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="Name" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="Type" nillable="true" type="xs:string"/>
<xs:element minOccurs="0" name="Users" nillable="true" type="tns:ArrayOfUser"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Node" nillable="true" type="tns:Node"/>
......
But now when I use bindings.xml, I get the following error
[ERROR] XPath evaluation of "wsdl:definitions/wsdl:types/xs:schema/xs:complexType[#name='Node']/xs:sequence/xs:element[#name='Type']" results in an empty target node
line 8 of file:/E:/projects/codegeneration/bindings.xml
What am I missing? I am using wsimport to generate the classes.
<xsd:import> does not actually change the WSDL file’s XML document tree. You have elements matching wsdl:definitions/wsdl:types/xs:schema/xs:import, not wsdl:definitions/wsdl:types/xs:schema/xs:complexType/xs:sequence/xs:element.
The JAX-WS specification’s “Customizations” chapter says:
Additionally, jaxb:bindings MAY appear inside a JAX-WS external binding file as a child of a jaxws:bindings element whose node attribute points to a xs:schema element inside a WSDL document. When the schema is processed, the outcome MUST be as if the jaxb:bindings element was inlined inside the schema document as an annotation on the schema component.
While processing a JAXB binding declaration (i.e. a jaxb:bindings element) for a schema document embedded inside a WSDL document, all XPath expressions that appear inside it MUST be interpreted as if the containing xs:schema element was the root of a standalone schema document.
So, your inner jaxws:bindings element must contain the XPath of the xs:schema element, not any of its descendants:
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema">
<jaxb:bindings node="xs:complexType[#name='Node']/xs:sequence/xs:element[#name='Type']">
<jaxb:class name="NodeTypeString"/>
</jaxb:bindings>
</jaxws:bindings>
I’m not sure if the above will actually work with a schema that uses <xsd:import>. You may have to refer to the imported schema explicitly:
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema">
<jaxb:bindings schemaLocation="https://abcserver.com/v2/two-way-ssl/MyService.svc?xsd=xsd2">
<jaxb:bindings node="xs:complexType[#name='Node']/xs:sequence/xs:element[#name='Type']">
<jaxb:class name="NodeTypeString"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxws:bindings>
I got two solutions for this issue I was facing.
I streamlined the wsdl schema by adding imported schema in it and removing import statements.
First build an episode using xjc for imported schema
xjc -episode myschema.episode myschema.xsd
And then use that episode as a binding in java classes generation through wsimport
wsimport mywsdl.wsdl -b myschema.episode
More about 2nd solution here

JiBX generates binding that ignores attribute namespace

I have the following schema (fragment):
<xs:complexType name="partnerPaymentsItemType">
<xs:sequence>
<xs:element name="changeTime" type="dateTime"/>
<xs:element name="statusId" type="shortId"/>
<xs:element name="paymentPointId" type="shortString"/>
<xs:element name="money" type="currency"/>
<xs:element name="paymentDestination" type="shortString"/>
<xs:element name="paymentDestinationType" type="shortId"/>
<xs:element name="subagentId" type="shortId" minOccurs="0"/>
<xs:element name="discountCardNumber" type="xs:string" minOccurs="0"/>
<xs:element name="amountAll" type="currency" minOccurs="0"/>
<xs:element name="rewardPercent" type="percentAmount" minOccurs="0"/>
<xs:element name="rewardPercentValue" type="percentAmount" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="paymentTime" use="required" type="dateTime"/>
<xs:attribute name="externalId" use="required" type="id"/>
<xs:attribute name="registeredId" use="required" type="id"/>
</xs:complexType>
I use JibX Codegen tool to generate sources from it, and then to compile binding that should allow me to unmarshal XML to Java objects. Here is my codegen settings:
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema"
delete-annotations="true"
prefer-inline="false"
generate-all="true"
show-schema="true"
type-substitutions="xs:date xs:string"
package="here.lays.my.package">
<class-decorator class="org.jibx.schema.codegen.extend.SerializableDecorator"/>
</schema-set>
Later, I try to parse an XML document which has namespace prefixes for both tags and attributes, which results an exception saying
Missing required attribute "paymentTime"
Debugging through JiBX sources shown that it tries to look for attribute with no namespace and name "paymentTime" in a document, while a document has an attribute with a namespace mapped to URL, and not able to find it of course.
I have decompiled binding with JAD and it searches for attribute with null namespace:
public static PartnerPaymentsItemType JiBX_beeline_binding_unmarshalAttr_1_93(PartnerPaymentsItemType arg1, UnmarshallingContext arg2)
throws JiBXException
{
arg2.pushTrackedObject(arg1);
arg1;
arg1.setPaymentTime(arg2.attributeText(null, "paymentTime"));
arg1.setExternalId(Utility.parseLong(WhitespaceConversions.trim(arg2.attributeText(null, "externalId"))));
arg1.setRegisteredId(Utility.parseLong(WhitespaceConversions.trim(arg2.attributeText(null, "registeredId"))));
arg2.popObject();
return arg1;
}
I would be grateful for any advise that could help resolving the issue - like, why JiBX generated such mapping, how to make it respect attribute namespace, and so on.
JiBX behavior was actually correct, namespace prefixes for attributes were not intended based on xsd.
Actual solution was to replace JiBX with XJC/JAXB and separate schema for the entity where I needed namespace prefixes for attributes.

specify type for multiple IDREF attributes in JAXB bindings

Apologies if this is a duplicate question, but I could not find anything for my situation. So here goes:
I have the following in an xsd file:
<xs:complexType name="Allocation">
<xs:annotation>
<xs:documentation>Links its owner to an xs:id.</xs:documentation>
</xs:annotation>
<xs:attribute name="idRef" type="xs:IDREF"/>
</xs:complexType>
<xs:complexType name="XYZ">
<xs:sequence>
<xs:element name="SomeAllocation" type="Allocation"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ABC">
<xs:sequence>
<xs:element name="SomeAllocation" type="Allocation"/>
</xs:sequence>
</xs:complexType>
I am try to generate fields/getters and setters in java that are of specific types for example XYZ.getSomeAllocation() should return type Object1 and ABC.getSomeAllocation() should return type Object2. The problem I am facing is that xjc is generating one Allocation class and the XYZ and ABC classes with the methods mentioned below returning java.lang.Object types.
Obviously creating to different Allocation types which are then used in the different objects solves the problem but I would like to reuse the object holding the xs:IDREF.
Your help is highly appreciated!
Thanks!

Does XSD allow simpleContent and complexContent at the same time?

I want to write an xsd for the xmlrpc spec (and generate java classes out of it using jaxb). The xmlrpc spec allows values like:
<value><int>123</int></value>
<value><boolean>1</boolean></value>
But at the same time it requires:
If no type is indicated, the type is string.
Which means i could receive something like this:
<value>test123</value>
which is equivalent to
<value><string>test123</string></value>
Is there a way to define this in an xsd.
Yes, set a mixed content model on value:
<xs:complexType name="valuetype" mixed="true">
<xs:sequence>
<xs:element name="int" type="xs:int"/>
<xs:element name="boolean" type="xs:boolean"/>
...
</xs:sequence>
</xs:complexType>

Categories

Resources