Tuesday, July 29, 2008

Working round xsd:choice binding issue with JAX-B 2.x

While JAX-B is pretty good most of the time it will fall over when trying to bind an xml schema that contains certain types of choice element. For example take the following snippet take from the XACML 2.0 standard schema:

<xs:element name="Policy" type="xacml:PolicyType" />
  <xs:complexType name="PolicyType">
  <xs:sequence>
    <xs:element ref="xacml:Description" minOccurs="0" />
    <xs:element ref="xacml:PolicyDefaults" minOccurs="0" />
    <xs:element ref="xacml:CombinerParameters" minOccurs="0" />
    <xs:element ref="xacml:Target" />
    <xs:choice maxOccurs="unbounded">
      <xs:element ref="xacml:CombinerParameters" minOccurs="0" />
      <xs:element ref="xacml:RuleCombinerParameters" minOccurs="0" />
      <xs:element ref="xacml:VariableDefinition" />
      <xs:element ref="xacml:Rule" />
    </xs:choice>
    <xs:element ref="xacml:Obligations" minOccurs="0" />
  </xs:sequence>
  <xs:attribute name="PolicyId" type="xs:anyURI" use="required" />
  <xs:attribute name="Version" type="xacml:VersionType" default="1.0" />
  <xs:attribute name="RuleCombiningAlgId" type="xs:anyURI" use="required" />
  </xs:complexType>
</xs:element>

If you try to run either the xjc or any of the web service import tools on this then then build will fail with the following message: 'Element "CombinerParameters" shows up in more than one properties.'. You will notice that in some cases of the choice the "CombinerParameters" property is duplicated.

Now one workaround is to refactor the schema to do this using sequences rather than choices; but of course you might not have control over the web service you are trying to use. Fortunately some-one at sun figure this out and there is a customization directive that will cause something sensible to be generated. This is called <xjc:simple> and while it is offically a vendor extension nearly everybody uses the sun implementation so there is not that much to worry about.

The examples linked above all uses embedded customizations; but of course you would never pollute your wsdl with java specific stuff information. So will use a binding file that looks like:

<?xml version="1.0" encoding="US-ASCII" ?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xs="http://www.w3.org/2001/XMLSchema"
              xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
              jxb:extensionBindingPrefixes="xjc">
  <jxb:globalBindings>
        <xjc:simple />
  </jxb:globalBindings>
</jxb:bindings> 

Problem solved you can now create a web service proxy for this type, hopefully this will be folded into a later version of JAXB.

6 comments:

otter606 said...
This comment has been removed by a blog administrator.
otter606 said...

Great tip, this worked a treat a similar problem with a MathML extension. Thanks, you saved me a lot of time!

S. Jabbar said...

I got this error in JDK 6 but not in JDK 5.

[ERROR] Element "{namespace}element" shows up in more than one properties

_DD said...

Thanks :D
Why is this so can you explain?

george said...

Thank you for this excellent and short solution. Superbe!

Gusthy said...

Thank you!
It worked very well!