How can I specify JAXB customizations externally to a WSDL file? - jaxb

I have a WSDL file for a service implemented in .NET. I also have the same file with some "customizations" made by a 3rd-party to make the file tolerable to wsimport, mostly of the form:
<s:annotation>
<s:appinfo>
<jaxb:property name="result"/>
</s:appinfo>
</s:annotation>
I'd like to be able to process the original WSDL from the vendor plus these overrides, but I'd like to specify them externally. I see that I can use the -b option for wsimport for "binding files" and I've tried to write an override file that currently looks like this:
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings node="//xs:element[#name='MyElementResult']">
<jxb:property name="result"/>
</jxb:bindings>
</jxb:bindings>
I've verified that "MyElementName" does in fact exist, in an element found here:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="vendor-uri"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s2="http://microsoft.com/wsdl/types/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="vendor-namespace"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
[...]
<s:element name="MyElementResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="MyElementResult" type="tns:Result" />
I'm getting this warning (and therefore no changes) from wsimport:
[ERROR] XPath evaluation of "//xs:element[#name='MyElementResult']" results in empty target node
line 4 of file:/Users/..../wsdl/custom-bindings.xjb
Am I missing something in my declaration(s)? Do I have my XPath expression incorrect? If I get my XPath/overrides working, is it formatted correctly in order to achieve the same result as if I had edited the original WSDL?
Is this even possible using external files, or will I have to re-modify any future versions of the WSDL with these same changes?

You need to give the schema location in your bindings XML file.
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings
schemaLocation="PATH_TO_YOUR_WSDL#types?schema1"
node="//xs:schema[#targetNamespace='SCHEMA_NAMESPACE']">
<jxb:bindings node="//xs:element[#name='MyElementResult']">
<jxb:property name="result"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
The #types?schema1 after the WSDL file name will specify which schema in the WSDL you are binding, starting at 1.

Related

Is there a way to ignore empty nodes in JAXB bindings file?

I am trying to create a generic .xjb bindings file to provide consistent Java classes generation from WSDLs / XSDs across multiple projects.
We generate the code via maven-jaxb2-plugin (Made by #lexicore).
The problem lies in the multiple projects part. If a particular binding instruction matches nothing in the provided XSD or WSDL, the class generation fails with
XPath evaluation of "<some_xpath_expression>" results in empty target node
How can I tell JAXB to ignore these cases so the bindings file can be used on any project without fine-tuning, regardless of the elements types used?
Here is a (stripped down) version showcasing the problem I have:
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
jxb:extensionBindingPrefixes="xjc">
<jxb:bindings schemaLocation="path/to/the/schema" node="/xs:schema">
<jxb:bindings multiple="true" node="//*[#type='xs:dateTime']">
<xjc:javaType name="java.time.LocalDateTime" adapter="a.b.c.LocalDateTimeAdapter" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
If I try to generate classes from a schema with no dateTime element, it will fail.
The objective is, in the end, to create something all projects of various teams could reuse without changing anything but the schemaLocation.
You need to set the required="no" attribute on the binding that you would like to allow not to match any node, i.e.
<jxb:bindings required="no" multiple="true" node="//*[#type='xs:dateTime']">
Depending on your context you may choose to say required="false" or required="0" as well.

JAXBElements generated from wsdl in Mule

We have a wsdl that we want to use in Mule studio. We generated the Java classes through the CXF component. There are a lot of elements in the schemas that are like this :
<xs:element minOccurs="0" name="SortIndex" nillable="true" type="xs:string"/>
In the generated Java classes, we get them as JAXBElement which is not really nice as it is hard to work with those in the DataMapper. I saw that this behavior can be overriden by providing jaxb bindings. However, this is how our wsdl looks now:
<wsdl:portType name="ILegacy">
<jaxws:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="src\main\resources\Legacy.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<enableWrapperStyle>false</enableWrapperStyle>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxws:bindings>
However, this doesnt change the generation of JAXBElements. Is there something wrong with this code?
Are you suing wsdl2java or xjc? or something else?
If you are using CXF wsdl2java or xjc pass in your binding file as a parameter to the command:
bindings123.xjb:
<jaxws:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="src\main\resources\Legacy.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<enableWrapperStyle>false</enableWrapperStyle>
<jaxb:globalBindings generateElementProperty="false"/>
</jaxws:bindings>
then use -b to pass the bindings file to jaxb:
xjc schema1.xsd schema2.xsd schema3.xsd -b bindings123.xjb

Unable to generate java.util.Calendar from xsd - getting XmlGregorianCalendar

Is it possible to generate entities with Claendar type fields from xsd files? I am trying both xs:date and xs:dateTime but still getting XMLGregarionCalendar. I am using cxf-codegen-plugin and jaxb bninding.
Thanks.
Paul.
When you generate your objects you can use a JAXB binding file, as demonstrated in Example 7 of the cxf-codegen-plugin documentation. Depending on what type you want to use (Calendar, Date, etc.), you will need to specify an appropriate adapter. To use Calendar, JAXB provides the adapter javax.xml.bind.DatatypeConverter. To use it with dateTime, date, and time, the JAXB bindings file should be
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings version="2.1"
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:globalBindings>
<!-- use Calendar instead of XMLGregorianCalendar -->
<jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/>
<jxb:javaType name="java.util.Calendar" xmlType="xs:date"
parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
printMethod="javax.xml.bind.DatatypeConverter.printDate"/>
<jxb:javaType name="java.util.Calendar" xmlType="xs:time"
parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
printMethod="javax.xml.bind.DatatypeConverter.printTime"/>
</jxb:globalBindings>
</jxb:bindings>
If you want to use Date instead, CXF provides org.apache.cxf.xjc.runtime.DataTypeAdapter in cxf-xjc-runtime.
Building on Patrick's answer, here is the XJC equivalent:
<jaxb:bindings version="2.1"
xmlns:jaxb="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">
<jaxb:globalBindings>
<!-- use Calendar Date instead of XMLGregorianCalendar -->
<jaxb:javaType name="java.util.Date" xmlType="xs:dateTime"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDateTime"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDateTime"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseDate"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printDate"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:time"
parseMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.parseTime"
printMethod="org.apache.cxf.xjc.runtime.DataTypeAdapter.printTime"/>
</jaxb:globalBindings>
</jaxb:bindings>

jaxb-generate classes from wsdl ,each schema classes should go to corrsponding package

i have one wsdl file which have schhemas included in it, i want to generate java classes for each schema in different package,please help me.
i have used following code,its generating classes related to all schemas
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jaxb:bindings schemaLocation="Event.xsd" node="/xsd:schema">
<jaxb:schemaBindings>
<jaxb:package name="com.event.dto" />
<jaxb:nameXmlTransform>
<jaxb:typeName suffix="CHASE"/>
</jaxb:nameXmlTransform>
For each shema file add xml like in your question, but with different name of
<jaxb:package name="com.event.dto" />

JAXB - Creating modules for reuse

Does JAXB support modular code generation?
Most of my background is with JibX for XML marshalling, but for legacy reasons our firm is using JAXB.
One feature that was available for JIBX was modular code generation. Say I have a main schema but I have several different envelopes for that schema. With JibX I could create a jar file out of the JibX'ed core schema, and then in separate projects I could JibX my envelope schemas and simply point to the shared jar instead of having to duplicate the code generation of the core schemas for each envelope.
I don't yet see a way for JAXB to handle this - has anyone been successful doing something like this?
Thanks in advance,
Roy
For the JAXB RI, that's handled with "episode" files (these are really just customization files). Process the core schema first, making sure to have xjc use the -episode <file> arg. Package the results of that processing into a JAR file with the episode file in META-INF/sun-jaxb.episode. Then, pass that JAR file as an arg to xjc when processing the other schemas.
Using a JAXB 2.1 implementation (Metro, EclipseLink MOXy, Apache JaxMe, etc), you can specify that schema types correspond to existing classes in order to prevent them from being generated.
For example:
root.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/root">
<xsd:import schemaLocation="imported.xsd" namespace="http://www.example.com/imported"/>
<xsd:complexType name="root">
<xsd:attribute name="root-prop" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
imported.xsd
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.com/imported"
targetNamespace="http://www.example.com/imported">
<xsd:complexType name="imported">
<xsd:attribute name="imported-prop" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
Problem Statement
If you use the XJC tool to generate java classes from the XML schema:
xjc -d out root.xsd
You the following is generated:
com\example\imported\Imported.java
com\example\imported\ObjectFactory.java
com\example\imported\package-info.java
com\example\root\ObjectFactory.java
com\example\root\Root.java
com\example\root\package-info.java
imported-bindings.xml
You can use a JAXB bindings file to specify that types from imported.xsd point to existing classes:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="imported.xsd">
<jxb:bindings node="//xs:complexType[#name='imported']">
<jxb:class ref="com.example.imported.Imported"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Running the XJC
Now if we run XJC with out bindings file:
xjc -d out -b imported-bindings.xml root.xsd
None of the files specified in the bindings file will be generated:
com\example\root\ObjectFactory.java
com\example\root\Root.java
com\example\root\package-info.java
Alternative Approach
The code generated from the imported schema directly (xjc imported.xsd) and indirectly (xjc root.xsd) is the same. You can simply drop the code generated indirectly and point at the project containing the code that was generated directly.

Resources