JAXB - Creating modules for reuse - jaxb

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.

Related

integrating an xsd validator (lib or tool)

I am currently using a crossplatform c++ project (windows+linux) which will soon need an external xsd validator.
My plan is to:
either find a c++ library which does xsd validation (possibly a complex task)
or an existing tool which I could just launch as an external process (easier I believe; Xerces could be an option?)
I have a deep hierarchy of xsd files, so I need a solid tool for the job.
My question: I need some suggestions about some easy-to-integrate-yet-production-ready-solution.
My take for now is to use Xerces, the java version and just call it in a separate process.
Probably I need to wrap Xerces, since it seems to not allow xsd validation in the command line, directly, e.g. https://github.com/ndw/xjparse.
Thanks
You could use xmllint with the --schema option:
xmllint --noout --schema test.xsd test.xml
test.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="info" type="xs:string"/>
</xs:schema>
test.xml
<?xml version="1.0"?>
<info>abc</info>

CXF JAXB basics Equals/Hashcode

I have a problem generating equals and hashcode methods for my imported xsd files which are output to a separate location to my wsdl files. I currently have a .wsdl and .xsd file in the same folder. The .wsdl file imports these xsd files which have a different namespace to the wsdl file. When these xsd files are generated they do not contain equals or hashcode methods. Below is a sample of my pom/xml config and files:
<wsdlOption>
<wsdl>
src/main/xml/wsdl/Rule.wsdl
</wsdl>
<wsdlLocation>classpath:wsdl/Rule.wsdl</wsdlLocation>
<bindingFiles>
<bindingFile>src/main/xml/wsdl/bindings.xjb</bindingFile>
</bindingFiles>
<extraargs>
<extraarg>-impl</extraarg>
<extraarg>-verbose</extraarg>
<extraarg>-xjc-XsimpleEquals</extraarg>
<extraarg>-xjc-XsimpleHashCode</extraarg>
</extraargs>
</wsdlOption>
Sample wsdl (imported Rule.xsd is not generating methods):
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.ws.com/Rule/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Rule"
targetNamespace="http://www.ws.com/Rule/">
<wsdl:types>
<xsd:schema targetNamespace="http://http://www.ws.com/Rule/">
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ws.com/Rule/"
xmlns:pref="http://www.xsd.com/Rule" xmlns:pref1="http://www.xsd.com/Common">
<xsd:import schemaLocation="Rule.xsd"
namespace="http://www.xsd.com/Rule">
</xsd:import>
<xsd:import schemaLocation="Common.xsd" namespace="http://www.xsd.com/Common"></xsd:import>
<xsd:element name="ListGrid">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="request"
type="pref:test" maxOccurs="1" minOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
I assume this is a problem with the location of the generated xsd as I can get it to work by moving this to the same parent folder as the wsdl namespace. I would like to get this to work without moving these files locations as I have a large codebase that would require a large refactor if I do this.
Any suggestions would be welcome.
I found a solution to this problem by adding the following to the pom.xml configuration:
<extraarg>-p</extraarg>
<extraarg>http://www.xsd.com/Rule=com.xsd.rule</extraarg>
Even though this does not change the namespace/package location it seems to now generate the imported files equals and hashcode methods.

XSD Validation: Use attribute in same file as definition?

I have a large .xsd file structured like this:
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns="foo:bar:baz" xmlns:quux="foo:bar:baz"
quux:attr1="A" quux:attr2="5">
<xsd:attribute name="attr1" type="xsd:string"/>
<xsd:attribute name="attr2" type="xsd:int"/>
<xsd:annotation>
<xsd:documentation>
<xhtml:h1 quux:attr1="A" quux:attr2="5">
Documentation here
</xhtml:h1>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType name=... />
</xsd:schema>
I get the error: "The foo:bar:baz:attr1" attribute is not declared.
Why is it not finding the attribute? It's right there. How can I make these attributes available to the documentation's header?
Future edit: the above schema got the green light from actual XML Validators. Guess there was just something Visual Studio was reading incorrectly.
The XSD you show can be imported or included into another XSD that includes an element declaration, but alone it cannot be used to validate an XML file because it does not declare even a single element.

Using JAXB episode files with wsimport

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.

XSD annotation and documentation elements, and how to use them

We are creating xml files that we want to be compliant with the following xsd: http://www.topografix.com/gpx/1/1/gpx.xsd This xsd supports '...extending by adding your own elements here ...', see the extensionsType, which I have copied below for convenience.
1) I don't understand whether annotation and documentation are literal element names that would appear in compliant xml. I believe they are not but need confirmation. I'm assuming then that a compliant document would simply have any number of our own custom elements anywhere inside of any [extensions] element, correct?
2) Why are there two pairs of annotation/documentation elements below, with one in a sequence?
<xsd:complexType name="extensionsType">
<xsd:annotation>
<xsd:documentation>
You can add extend GPX by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
You can add extend GPX by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
</xsd:any>
</xsd:sequence>
</xsd:complexType>
1) From the XML Schema specification: "Annotations provide for human- and machine-targeted annotations of schema components." Schema authors use xsd:documentation as, say Java or .NET, developers use comments.
Annotations are XML Schema artifacts; they are not to show up in an XML document. And yes, your extensions elements should go under <extensions/>; you may use any namespace, other than http://www.topografix.com/GPX/1/1
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="creator1" xmlns="http://www.topografix.com/GPX/1/1">
<extensions>
<my:element xmlns:my="urn:tempuri-org:some">Hello!</my:element>
</extensions>
</gpx>
2) Hard to say why there are two with the same comment; the difference though is that one documents the complex type, while the other the xsd:any element. I would personally have used different comments, first to explain what the complex type is for, the second just as shown.

Resources