There are two WSDLs which share some of schemas they use to define their datatypes. Here is an example of one of the WSDLs:
<wsdl:definitions
name="FooService"
targetNamespace="http://xmlns.my.org/services/FooService/v001"
xmlns:srv="http://xmlns.my.org/services/FooService/v001"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:fault="java:org.my.exception"
...
>
<wsdl:types>
<xsd:schema>
<xsd:import namespace="java:org.my.exception" schemaLocation="../xsd/common/BusinessException.xsd"/>
<xsd:import namespace="http://xmlns.my.org/services/FooServiceMessages/v001" schemaLocation="../xsd/fooservice/FooServiceMessages_v001.xsd"/>
</xsd:schema>
</wsdl:types>
...
<wsdl:message name="BusinessException">
<wsdl:part element="fault:BusinessException" name="BusinessException"/>
</wsdl:message>
...
<wsdl:portType name="IFooService">
<wsdl:operation name="getItems">
...
<wsdl:fault message="srv:BusinessException" name="BusinessException"/>
</wsdl:operation>
...
</wsdl:portType>
...
</wsdl:definitions>
BusinessException.xsd is one of the common schemes.
I'm trying to generate Java code by these WSDLs with wsimport. It would be reasonable to compile common schemas separately from WSDLd and then reuse classes derived from these schemas while compiling WSDLs. For this purpose I've generated a JAXB episode file along with common Java code:
<bindings version="2.1" xmlns="http://java.sun.com/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="java:org.my.exception">
<schemaBindings map="false">
<package name="org.my.integration.dto.common"/>
</schemaBindings>
<bindings scd="~tns:BusinessException">
<class ref="org.my.integration.dto.common.BusinessException"/>
</bindings>
</bindings>
<bindings scd="x-schema::tns" xmlns:tns="http://xmlns.my.org/BaseIdentifiers/v001">
<schemaBindings map="false">
<package name="org.my.integration.dto.common"/>
</schemaBindings>
<bindings scd="~tns:EntityIdentifierListType">
<class ref="org.my.integration.dto.common.EntityIdentifierListType"/>
</bindings>
<bindings scd="~tns:...">
<class ref="..."/>
</bindings>
...
</bindings>
</bindings>
http://xmlns.my.org/BaseIdentifiers/v001 namespace is filled with another common schema that's imported in FooServiceMessages_v001.xsd (actually in a schema that's imported in a schema that's ... that's imported in FooServiceMessages_v001.xsd).
Here is a wsimport call which I use to generate Java code:
wsimport -B-XautoNameResolution -Xnocompile -s ./../java/ -verbose -b ./bindings/fooservice/jaxws-bindings.xml -b ./bindings/fooservice/jaxb-bindings.xml -b ./bindings/common/common.episode -keep ./wsdl/FooService_v001.wsdl
The following error occurs on this call:
[ERROR] Schema descriptor {java:org.my.exception}BusinessException in message part "BusinessException" is not defined and could not be bound to Java. ...
BTW if a binding for BusinessException.xsd is described in a plain external JAXB binding file (not in a episode file) all works fine. Looks like wsimport has some problems with handling episode files which describe bindings for schemes which are imported in WSDL directly.
Is there a way to use episode files with wsimport for schemes directly imported in WSDL (like BusinessException.xsd in my case)?
As https://github.com/javaee/jaxb-v2/issues/514 says it is impossible to generate sources for WSDL using JAXB episodes.
Sun/Oracle engineers unable to implement necessary enhancement for 11 years (2008-2019). And recently Oracle thrown sources to Eclipse project (October 2018).
I generate WSDL binding without episodes, as final step I remove packages from common schema. For Gradle it looks like:
wsimport {
wsdl = file("${project.rootDir}/wsdl/PingService.wsdl")
bindings = files(...)
}
task('afterWsimport', type: Delete) {
delete new File(file(wsimport.javaDir), "com/bla/schema")
delete new File(file(wsimport.javaDir), "com/foo")
}
wsimport.finalizedBy(afterWsimport)
It seems that this is some kind of bug or incorrect behavior of wsimport. wsdl2java tool from Apache CXF lacks this problem.
Related
I am working on an application that uses XJC to generate Java POJOs from XSDs. There are dozens of schemas, and that number will grow. The application also needs to be able to handle different versions of the same schema, which means that I will have multiple schemas defining common types. I am trying to customize the bindings so that certain core types implement a common interface. The Inheritance plugin of JAXB2 Basics seems to do what I need, but I can't seem to nail the right syntax.
Here is the relevant part of my schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://example.com/core"
targetNamespace="http://example.com/core"
xmlns:xml="http://www.w3.org/XML/1998/namespace">
...
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="Address" type="xs:string"/>
<xs:element name="City" type="xs:string"/>
<xs:element name="Province" type="xs:string"/>
<xs:element name="Country" type="xs:string"/>
<xs:element name="County" type="xs:string" minOccurs="0"/>
<xs:element name="PostalCode" type="xs:string"/>
</xs:sequence>
</xs:complexType>
...
</xs:schema>
... and this is what my custom binding file looks like:
<?xml version="1.0"?>
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
xmlns:my="http://example.com/core"
jaxb:extensionBindingPrefixes="inheritance"
version="2.1">
<jaxb:bindings scd="x-schema::my" xmlns:my="http://example.com/core">
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
<jaxb:bindings scd="/type::my:addressType">
<inheritance:implements>com.mysite.validator.ValidatableAddress</inheritance:implements>
<!--<xjc:superInterface name="com.mysite.validator.ValidatableAddress"/>-->
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
I'm using the scd approach, because in all the "traditional" binding examples that show how to use the inheritence plugin, schemaLocation is specified. I want to avoid having to specify schemaLocation because of our large (and growing) number of schemas. I don't want to have to change the binding file every time we add a new schema. So, scd seems like it will satisfy this requirement.
However when I run the build using the above binding, I get this:
[xjc] [ERROR] cvc-elt.1: Cannot find the declaration of element 'inheritance:implements'.
[xjc] line 18 of file:/dev/workspace/my_app/etc/schemas/bindings-common.xml
[xjc] failure in the XJC task. Use the Ant -verbose switch for more details
[xjc] classLoader = java.net.URLClassLoader#ebcdbb
[xjc] SharedSecrets.getJavaNetAccess()=java.net.URLClassLoader$7#14562c5
If I comment out the inheritance:implements line and uncomment the xjc:superInterface line, the error goes away and the build completes successfully, but my AddressType classes don't implement the ValidatableAddress type.
Can the inheritence plugin be used with scd? Can xjc:superInterface be limited to only certain elements?
Cheers.
Author of jaxb2-basics here.
See this issue in XJC. In short, XJC for some reason does not allow custom/vendor customization elements in SCD bindings.
inheritance:implements is such customization element.
So no, this does not work due a problem in XJC.
I personally bind via schemaLocation and XPath but use a "virtual" schema location URI and rewrite it via catalogs.
SCD would have been a much better choice (you're absolutely right here) but it just does not work.
Update on virtual schema location and catalogs.
Here's an example of binding which customizes some complex type:
<jaxb:bindings
schemaLocation="http://schemas.opengis.net/wps/2.0/wpsCommon.xsd"
node="/xs:schema">
<jaxb:bindings node="xs:element[#name='Data']/xs:complexType">
<wildcard:lax/>
</jaxb:bindings>
</jaxb:bindings>
It is bound via schemaLocation and XPath. The schemaLocation is an existing URL, but in the build it is rewritten via catalog into the resource inside a Maven artifact:
REWRITE_SYSTEM "http://schemas.opengis.net" "maven:org.jvnet.ogc:ogc-schemas:jar::!/ogc"
So basically http://schemas.opengis.net/wps/2.0/wpsCommon.xsd will be loaded from the ogc-schema.jar!/ogc/wps/2.0/wpsCommon.xsd.
Using maven-jaxb2-plugin you can refer to binding files inside Maven artifacts as well:
<binding>
<dependencyResource>
<groupId>${project.groupId}</groupId>
<artifactId>ows-v_2_0</artifactId>
<resource>ows-v_2_0.jsonix.xjb</resource>
<version>${project.version}</version>
</dependencyResource>
</binding>
So, in combination, it allows writing binding files once and reuse them across modules.
But this was all a huge pain to figure out. I did it for the ogc-schemas project which is now some 50 heavily interconnected schemas. I heavily suffer from XJC drawbacks and issues, but this is the best possible at the moment. I even thought about forking and patching XJC, but this is far of effort limits I can afford.
So I've ended up with a number of mindblogging workarounds which somehow do the job at the end of the day.
Thanks to lexicore for the prompt and detailed answers. However that approach wasn't working for me, so I ended up with the following solution...
Because I am using Ant to invoke XJC, I ended up leveraging Ant's <copy filtering="true"...> capabilities to dynamically generate the binding file.
Here is my binding "template" file (bindings-common.xml):
<?xml version="1.0"?>
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
xmlns:my="http://http://example.com/core"
jaxb:extensionBindingPrefixes="inheritance"
version="2.1">
<jaxb:bindings>
<jaxb:globalBindings localScoping="toplevel">
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
</jaxb:bindings>
<jaxb:bindings
schemaLocation="#bindingSchema#"
node="/xs:schema">
<jaxb:bindings node="//xs:complexType[#name='addressType']">
<inheritance:implements>com.example.validator.ValidatableAddress</inheritance:implements>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Note this line:
<jaxb:bindings
schemaLocation="#bindingSchema#"
node="/xs:schema">
This variable will get populated by Ant for each of the schemas that I am processing:
<property name="jaxb.binding.template" value="../etc/form-schemas/bindings-common.xml"/>
<property name="jaxb.binding.file" value="${jaxb.src.dir}/bindings-common${schema.version}.xml"/>
<echo message="Filtering ${jaxb.binding.file} using template ${jaxb.binding.template}"/>
<copy file="${jaxb.binding.template}"
tofile="${jaxb.binding.file}"
filtering="true">
<filterset>
<filter token="bindingSchema" value="../../etc/form-schemas/${schema.version}/common.xsd"/>
</filterset>
</copy>
<xjc destdir="${jaxb.src.dir}"
extension="true"
schema="${schema.file}"
package="${package}"
binding="${jaxb.binding.file}">
<arg value="-episode"/>
<arg value="${jaxb.src.dir}/common${schema.version}.episode"/>
<arg line="-Xinheritance"/>
<!-- Plugins -->
<classpath>
<fileset dir="../build-libs/">
<!-- JAXB2 Basics library -->
<include name="jaxb2-basics-0.6.4.jar"/>
<!-- JAXB2 Basics library dependencies -->
<include name="jaxb2-basics-runtime-0.6.4.jar"/>
<include name="jaxb2-basics-tools-0.6.4.jar"/>
<include name="javaparser-1.0.8.jar"/>
<include name="commons-beanutils-*.jar"/>
<include name="commons-lang-*.jar"/>
<include name="commons-logging-*.jar"/>
</fileset>
</classpath>
</xjc>
</target>
Hopefully this will help future generations of JAXB victims.
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
I have created a new JAXB project and imported an xsd which I am trying to generate JAXB classes off of. When I select "Generate->JAXB Classes" I get a number of similar errors all which relate to naming conflicts:
A class/interface with the same name "generated.Document" is already in use. Use a class customization to resolve this conflict.
The above error is thrown from the following piece of the .xsd file
<xs:complexType name="Document">
<xs:sequence>
<xs:element ref="Document"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Document">
...
Changing the .xsd file is not an option for me so I have to find another way. I have been reading about the possibility of creating a bindings file. I can't seem to find good documentation on how to do that for my particular problem. My three main questions are:
Should I create a new bindings .xjb file and add it to eclipse to solve this issue?
How should this bindings file look in order to resolve the "Document" naming conflicts?
How do I get eclipse to recognize the bindings file when I run "Generate -> JAXB Classes
Should I create a new bindings .xjb file and add it to eclipse to solve this issue?
yes, you can with an xjb file
How should this bindings file look in order to resolve the "Document" naming conflicts?
(e.g. I don't know your entire xsd, this is only an example)
<bindings version="2.0" xmlns="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"
xmlns:annox="http://annox.dev.java.net">
<bindings node="xs:complexType[#name='Document']">
<class name="Item"/>
</bindings>
</bindings>
How do I get eclipse to recognize the bindings file when I run "Generate -> JAXB Classes
Eclipse allows you to attach an XJB file (Binding files:)
I hope I've given you all the answers about your question.
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.
I have three different JAX-WS services which use the same classes on the server (e.g. ServiceA, ServiceB, and ServiceC, all of which use MyCommonClass as a parameter). Another module we are developing is using wsimport to create a client for these services, however the problem is that wsimport creates separate instances of MyCommonClass for each service:
com.company.servicea.endpoint.MyCommonClass
com.company.serviceb.endpoint.MyCommonClass
etc.
I know that I could use the wsimport -p option to specify a common package for each endpoint, however I'd like to keep most of the classes in separate packages, but just to share certain common ones. From what I have read it sounds like a JAXB bindings file(s) might be able to help, but I haven't yet figured out the exact syntax to achieve the desired result. I think I'll need a separate bindings file for each service (as I call wsimport once for each one), which looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.1" xmlns:tns="http://endpoint.servicea.company.com/">
<bindings node="//xsd:complexType[#name='myCommonClass']">
<class name="com.company.model.MyCommonClass"/>
</bindings>
</bindings>
Am I on the right track? Or do you have any alternative solutions to the problem?
Define your common classes in an xsd and import it in to the service WSDL's.
Then use the schema customization to generate definitions in this schema in to a separate package like "com.company.model"
<jxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="1.0">
<jxb:bindings schemaLocation="model.xsd" node="/xsd:schema">
<jxb:schemaBindings>
<jxb:package name="com.company.model"/>
</jxb:schemaBindings>
</jxb:bindings>
...
ref: http://jax-ws.java.net/jax-ws-21-ea1/docs/customizations.html#2.6_Class_Customization