I have two XSD documents over which I have no control - i.e. I cannot force their authors to change them. Unfortunately, the XSDs are not valid when used side by side, because they contain conflicting definitions:
<!-- first.xsd -->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:onl="http://example/data/online" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example/data/online" elementFormDefault="qualified" attributeFormDefault="unqualified" version="2.4">
<xs:element name="content">
<xs:complexType>
<xs:sequence>
<xs:element name="docSeqId" type="xs:long">
<xs:annotation>
<xs:documentation>Identifier of a documentation sequence.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="customerName" type="xs:string">
<xs:annotation>
<xs:documentation>Name of a customer.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<!-- second.xsd -->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:onl="http://example/data/online" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example/data/online" elementFormDefault="qualified" attributeFormDefault="unqualified" version="2.4">
<xs:element name="content">
<xs:complexType>
<xs:sequence>
<xs:element name="transactionId" type="xs:long">
<xs:annotation>
<xs:documentation>Id of a transaction.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="amount" type="xs:decimal">
<xs:annotation>
<xs:documentation>Transaction amount.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="targetAccountId" type="xs:string">
<xs:annotation>
<xs:documentation>Id (GUID) of a target account.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
I created the following jaxb2-maven-plugin
configuration:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources/</outputDirectory>
</configuration>
<executions>
<execution>
<id>generate-source-code</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>src/main/resources/integration/first.xsd</source>
<source>src/main/resources/integration/second.xsd</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
but when I execute relevant maven phase, the build exits with the following error:
[ERROR] file:/C:/Users/Andy/development/sample-project/src/main/resources/integration/second.xsd [23,18] org.xml.sax.SAXParseException: 'content' is already defined
How can I generate valid Java code from the XSD files, so that I can use them?
I figured out I was facing two issues:
Content
class in a same package - which obviously does not work,jaxb2-maven-plugin
to process them simultaneously.In order to solve the first of the two problems, I use two .xjb
(XML-to-Java binding file, one for each of the invalid .xsd
s), where I defined in which Java package source code from a given .xsd
should be placed.
The binding files look like this:
<!-- first.xjb -->
<jxb:bindings version="3.0"
xmlns:jxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="../integration/first.xsd" node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="example.data.online.first"/>
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
<!-- second.xjb -->
<jxb:bindings version="3.0"
xmlns:jxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="../integration/second.xsd" node="//xsd:schema">
<jxb:schemaBindings>
<jxb:package name="example.data.online.second"/>
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
Using the binding, (among other things), I was able to override the target Java package.
I solved the second problem by creating two separate executions of the jaxb2-maven-plugin
, one for each of the conflicting .xsd
s, and each of them using their relevant .jxb
binding file.
Important: By default, jaxb2-maven-plugin
clears the output directory before each generation execution. In my case I want to merge generated code together, this can be done by setting the clearOutputDir
argument to false
.
The final configuration of the plugin looks like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources/</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
<executions>
<execution>
<id>first-generator</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>src/main/resources/integration/first.xsd</source>
</sources>
<xjbSources>
<xjbSource>src/main/resources/jaxb2/first.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
<execution>
<id>second-generator</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>src/main/resources/integration/second.xsd</source>
</sources>
<xjbSources>
<xjbSource>src/main/resources/jaxb2/second.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
</executions>
</plugin>
leading to correct Java code generation: