0

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?

Andy
  • 1,127
  • 2
  • 12
  • 25

1 Answers1

0

I figured out I was facing two issues:

  1. generation would lead to same classes, i.e. I would have duplicate definition of Content class in a same package - which obviously does not work,
  2. conflicting XSD files, which would not allow 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 .xsds), 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 .xsds, 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:

generated Java beans from XSD

Andy
  • 1,127
  • 2
  • 12
  • 25