wsimport - 'XXX' is already defined, the first definition appears here

59.1k views Asked by At

I am generating Java classes using a WSDL file that imports and includes a whole slew of other schemas and DTDs, which in turn reference each other. (It is the infamous 'standard' XTA2 V3 WSDL file, to name names. Standard in quotes because one would assume that a standard WSDL file can be generated with standard tools without requiring patches.)

The error messages I get look like this:

[ERROR] 'NonEmptyStringType' is already defined
  Zeile 17 von file:/C:/Users/itbc000257/Documents/projekte/km-tafe/src/main/resources/META-INF/wsdl/OSCI_MessageMetaData_V2.02.xsd
[ERROR] (related to above error) the first definition appears here
  Zeile 12 von file:/C:/Users/itbc000257/Documents/projekte/km-tafe/src/main/resources/META-INF/wsdl/OSCI_MessageMetaData_V2.02.xsd
1

There are 1 answers

1
dschulten On BEST ANSWER

The error was caused by schema imports where one schema referenced the schemaLocation with a relative path, whereas the others use an absolute http URL.

OSCI2_02.xsd uses a relative schemaLocation:

<xs:import namespace="http://www.osci.eu/ws/2014/10/transport"
  schemaLocation="OSCI_MessageMetaData_V2.02.xsd"/>

XTA.wsdl, XTA-synchron.wsdl, XTA-Webservice-Datentypen.xsd, XTA-Webservice-Globale-Elemente.xsd use an absolute schemaLocation URL:

<xsd:import namespace="http://www.osci.eu/ws/2014/10/transport"
  schemaLocation="http://www.osci.eu/ws/2014/10/transport/OSCI_MessageMetaData_V2.02.xsd"/>

There is a long-standing bug in xjc from the jaxb-ri which mishandles this problem, and a proposed fix by the late Highsource, which never made it into the product.

In my case, the workaround was to download all related schemas, patch the OSCI2_02.xsd schema import to use the absolute URL and create a jax-ws-catalog.xml, so that wsimport uses my patched schema rather than downloading the broken file from the Internet.

Find my setup below.

WSDL recursive download for schema files:

#!/bin/bash
# Anthony/Rabiaza
# 2018-02-31
# https://github.com/anthonyrabiaza/recursiveDownloader
# Patch by dschulten: load from absolute URLs and do not download already existing files to avoid endless loops

#wget parameters:
# -T 60: timeout of 60 sec
# -nv: non verbose
# -nc: skip downloads that would download to existing files
# --secure-protocol=TLSv1 --no-check-certificate: security related
wget_params="-T 60 -nv -nc --secure-protocol=TLSv1 --no-check-certificate


function help() {
    echo "Please run this utility with the URL of the WSDL/XSD as argument"
    echo -e "\tFor instance:"
    echo -e "\t$0 http://192.168.0.96:8080/HelloWorld_WebServiceProject/wsdl/HelloWorld.wsdl"
}

function download() {
    export filename=${1##*/}
    if [ "$filename" == "" ];
    then
        echo -e "\tError for $1"
        echo -ne "\t\t"
        return -1
    fi
    echo -e "\tDownloading $filename"
    echo -en "\t\twget -> "
    wget $wget_params $1
    echo ""
}

function getDependencies() {
    export nbOccurrences=`grep -Po 'schemaLocation' $1 | wc -l`

    echo "Grepped $nbOccurrences in $1"

    if [ $nbOccurrences -gt 0 ];
        then
            export dependencies=`grep -Po 'schemaLocation="\K.*?(?=")' $1`
            echo "$dependencies" | while read -r dependency
            do
                if [ ! -f ${dependency##*/} ] ; then
                    download $dependency
                    echo Filename: ${dependency##*/}
                    getDependencies ${dependency##*/}
                fi
            done
        else
            echo -e "\t\tNo more dependencies for $1"
    fi

}

if [ $# -lt 1 ];
    then help
    exit -1
fi

currentDir="$PWD"

echo "Recursive Downloader"
echo "Command:    $0"
echo "Parameters: $*"
echo ""
echo "Creating output folder"

mkdir -p output
cd output

export filename=${1##*/}
export serverPath=${1%/*}

echo "File to download $filename on $serverPath"

download $1

getDependencies $filename $serverPath

cd "$currentDir"

The script doesn't download DTDs, so I also had to download:

All downloaded files go into src/main/resources/META-INF/wsdl.

The following jax-ws-catalog.xml file in the same folder tells wsimport to look for the downloaded files rather than downloading them from the Internet:

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
    <system systemId="http://www.osci.eu/ws/2014/10/transport/OSCI_MessageMetaData_V2.02.xsd"
            uri="OSCI_MessageMetaData_V2.02.xsd"/>
    <system systemId="http://www.w3.org/2006/03/addressing/ws-addr.xsd" uri="ws-addr.xsd"/>
    <system systemId="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
            uri="oasis-200401-wss-wssecurity-secext-1.0.xsd"/>
    <system systemId="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
            uri="oasis-200401-wss-wssecurity-utility-1.0.xsd"/>
    <system systemId="http://www.w3.org/2001/xml.xsd" uri="xml.xsd"/>
    <system systemId="http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd" uri="xmldsig-core-schema.xsd"/>
    <system systemId="http://xoev.de/schemata/basisdatentypen/1_1/xoev-basisdatentypen.xsd"
            uri="xoev-basisdatentypen.xsd"/>
    <system systemId="http://www.osci.eu/ws/2014/10/transport/OSCI2_02.xsd" uri="OSCI2_02.xsd"/>
    <system systemId="http://www.w3.org/2007/02/ws-policy.xsd" uri="ws-policy.xsd"/>
    <system systemId="http://xoev.de/transport/xta/211/XTA-Webservice-Globale-Elemente.xsd"
            uri="XTA-Webservice-Globale-Elemente.xsd"/>
    <system systemId="http://xoev.de/transport/xta/211/xenc-schema.xsd" uri="xenc-schema.xsd"/>
    <system systemId="http://xoev.de/transport/xta/211/XTA-Webservice-Exceptions.xsd"
            uri="XTA-Webservice-Exceptions.xsd"/>
    <system systemId="http://www.w3.org/2003/05/soap-envelope/" uri="soap-envelope.xsd"/>
    <system systemId="http://www.w3.org/2001/XMLSchema.dtd" uri="XMLSchema.dtd"/>
</catalog>

Here my jaxws-maven-plugin definition which uses the jakarta-ee edition of the plugin (suitable above Java 8), together with the patrodyne hisrc-basicjaxb-plugins for jakarta-ee XML for generation of toString, etc.:

<plugin>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>3.0.0</version>
    <executions>
        <execution>
            <goals>
                <goal>wsimport</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <wsdlDirectory>src/main/resources/META-INF/wsdl</wsdlDirectory>
        <wsdlFiles>
            <wsdlFile>XTA.wsdl</wsdlFile>
        </wsdlFiles>
        <wsdlLocation>/META-INF/wsdl/XTA.wsdl</wsdlLocation>
        <vmArgs>
            <!-- Needed for file access to datatypes.dtd in the local file system -->
            <vmArg>-Djavax.xml.accessExternalDTD=all</vmArg>
        </vmArgs>
        <args>-XadditionalHeaders</args>
        <catalog>src/main/resources/META-INF/wsdl/jax-ws-catalog.xml</catalog>
        <extension>true</extension>
        <xjcArgs>
            <xjcArg>-XfluentAPI</xjcArg>
            <xjcArg>-XsimpleToString</xjcArg>
            <xjcArg>-XsimpleEquals</xjcArg>
            <xjcArg>-XsimpleHashCode</xjcArg>
        </xjcArgs>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.patrodyne.jvnet</groupId>
            <artifactId>hisrc-basicjaxb-plugins</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>
</plugin>

And finally, the generated classes need jakarta.xml dependencies:

<properties>
    <jakarta.xml.version>4.0.1</jakarta.xml.version>
</properties>

<dependency>
    <groupId>jakarta.xml.ws</groupId>
    <artifactId>jakarta.xml.ws-api</artifactId>
    <version>${jakarta.xml.version}</version>
</dependency>