javajax-wstroubleshootingweb-services

JAX-WS wsimport エラー: 複雑な WSDL のコード生成失敗を修正する方法

SOAPless Team8 min read

wsimport は JAX-WS 標準の WSDL からの Java クライアントコード生成ツールです。シンプルなサービスでは問題なく動作しますが、複雑な型定義、複数スキーマ、非標準パターンを含むエンタープライズ WSDL に遭遇した途端、難解なエラーを吐き始めます。本記事では、よく遭遇するエラーとその具体的な修正方法を解説します。

エラー 1: 「Two Declarations Cause a Collision」

複雑な WSDL で最も頻繁に遭遇する wsimport エラーです。JAXB (wsimport 内部の XML-Java バインディング層) が同じ名前の Java クラスやプロパティを 2 つ生成しようとした場合に発生します。

[ERROR] Two declarations cause a collision in the ObjectFactory class.
  line 42 of file:/path/to/service.wsdl
[ERROR] (Related to above error) This is the other declaration.
  line 87 of file:/path/to/service.wsdl

発生原因

JAXB は XML の要素名を命名規則に基づいて Java クラス名にマッピングします。例えば getUser (要素) と GetUser (complexType) は、どちらも Java クラス GetUser にマッピングされ、衝突が発生します。

修正方法: JAXB バインディングカスタマイズファイル

jaxb-binding.xml を作成して名前衝突を解決します:

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
               version="3.0">

  <!-- 衝突している型の名前を変更 -->
  <jaxb:bindings schemaLocation="service.wsdl#types?schema1">
    <jaxb:bindings node="//xs:complexType[@name='GetUser']">
      <jaxb:class name="GetUserType"/>
    </jaxb:bindings>
  </jaxb:bindings>

  <!-- または全体にサフィックスルールを適用 -->
  <jaxb:bindings>
    <jaxb:nameXmlTransform>
      <jaxb:typeName suffix="Type"/>
    </jaxb:nameXmlTransform>
  </jaxb:bindings>

</jaxb:bindings>

wsimport に渡して実行します:

wsimport -keep -b jaxb-binding.xml -d output/ service.wsdl

衝突が多数ある場合は、グローバルな設定がより実用的です:

<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb" version="3.0">
  <jaxb:globalBindings>
    <jaxb:serializable uid="1"/>
    <jaxb:javaType name="java.util.Calendar"
                    xmlType="xs:dateTime"
                    parseMethod="jakarta.xml.bind.DatatypeConverter.parseDateTime"
                    printMethod="jakarta.xml.bind.DatatypeConverter.printDateTime"/>
  </jaxb:globalBindings>
</jaxb:bindings>

エラー 2: 「Undefined Element Declaration」

[ERROR] undefined element declaration 's:schema'
  line 15 of https://api.example.com/service.asmx?wsdl

このエラーは .NET (ASMX や WCF) の Web サービスで非常に多く見られます。Microsoft 固有のスキーマ拡張や非標準のプレフィックスを使用しているスキーマを参照している場合に発生します。

修正方法: WSDL をダウンロードして修正する

# WSDL をローカルにダウンロード
curl -o service.wsdl "https://api.example.com/service.asmx?wsdl"

問題のある要素を修正します。s:schema の問題は通常、不足しているスキーマインポートの追加で解決します:

<!-- <wsdl:types> セクション内に追加 -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:import namespace="http://www.w3.org/2001/XMLSchema"/>
</xs:schema>

あるいは、ベンダー拡張を有効にする -extension フラグを使用します:

wsimport -keep -extension -d output/ service.wsdl

エラー 3: エンコーディングの非対応

[ERROR] unsupported encoding: windows-1252

レガシーな WSDL ファイルが UTF-8 以外のエンコーディングを宣言していることがあります。最新のツールではサポートされていない場合があります。

修正方法: エンコーディングを変換する

# ダウンロードして UTF-8 に変換
curl -o service-original.wsdl "https://api.example.com/service?wsdl"
iconv -f WINDOWS-1252 -t UTF-8 service-original.wsdl > service.wsdl

# XML 宣言を更新
# 変更前: <?xml version="1.0" encoding="windows-1252"?>
# 変更後: <?xml version="1.0" encoding="UTF-8"?>

エラー 4: パッケージ名の衝突

WSDL が異なる名前空間を持つ複数のスキーマをインポートしている場合、wsimport は各名前空間を Java パッケージにマッピングします。2 つの名前空間が同じパッケージ名を生成するとコンパイルに失敗します。

[ERROR] Two classes have the same name
  "com.example.generated.ObjectFactory"

修正方法: 明示的なパッケージマッピング

wsimport -keep \
  -p com.example.orders \
  -b package-binding.xml \
  -d output/ \
  service.wsdl

スキーマ単位で制御するバインディングファイル:

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
               xmlns:xs="http://www.w3.org/2001/XMLSchema"
               version="3.0">

  <jaxb:bindings schemaLocation="service.wsdl#types?schema1">
    <jaxb:schemaBindings>
      <jaxb:package name="com.example.orders.types"/>
    </jaxb:schemaBindings>
  </jaxb:bindings>

  <jaxb:bindings schemaLocation="service.wsdl#types?schema2">
    <jaxb:schemaBindings>
      <jaxb:package name="com.example.orders.common"/>
    </jaxb:schemaBindings>
  </jaxb:bindings>

</jaxb:bindings>

エラー 5: Java 11 以降のモジュールシステム問題

Java 11 以降、JAX-WS は JDK から削除されました。以下のようなエラーが発生します:

error: package javax.xml.ws does not exist
error: package javax.jws does not exist

修正方法: Jakarta XML Web Services 依存関係を追加

Java 11 以降では外部依存関係が必要です。Maven の場合:

<dependencies>
  <!-- JAX-WS ランタイム -->
  <dependency>
    <groupId>jakarta.xml.ws</groupId>
    <artifactId>jakarta.xml.ws-api</artifactId>
    <version>4.0.2</version>
  </dependency>
  <dependency>
    <groupId>com.sun.xml.ws</groupId>
    <artifactId>jaxws-rt</artifactId>
    <version>4.0.3</version>
    <scope>runtime</scope>
  </dependency>

  <!-- JAXB (同じく JDK から削除済み) -->
  <dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.2</version>
  </dependency>
  <dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.5</version>
    <scope>runtime</scope>
  </dependency>
</dependencies>

JDK 同梱の wsimport ではなく、Jakarta ディストリビューションのスタンドアロン版を使用します:

<!-- Maven プラグインで wsimport を実行 -->
<plugin>
  <groupId>com.sun.xml.ws</groupId>
  <artifactId>jaxws-maven-plugin</artifactId>
  <version>4.0.3</version>
  <executions>
    <execution>
      <goals><goal>wsimport</goal></goals>
      <configuration>
        <wsdlUrls>
          <wsdlUrl>https://api.example.com/service?wsdl</wsdlUrl>
        </wsdlUrls>
        <packageName>com.example.service</packageName>
        <keep>true</keep>
        <extension>true</extension>
        <bindingFiles>
          <bindingFile>${basedir}/src/main/resources/jaxb-binding.xml</bindingFile>
        </bindingFiles>
      </configuration>
    </execution>
  </executions>
</plugin>

Gradle の場合:

plugins {
    id 'java'
}

configurations {
    jaxws
}

dependencies {
    jaxws 'com.sun.xml.ws:jaxws-tools:4.0.3'
    implementation 'jakarta.xml.ws:jakarta.xml.ws-api:4.0.2'
    runtimeOnly 'com.sun.xml.ws:jaxws-rt:4.0.3'
}

tasks.register('wsimport', JavaExec) {
    classpath = configurations.jaxws
    mainClass = 'com.sun.tools.ws.WsImport'
    args '-keep',
         '-extension',
         '-d', "${buildDir}/generated-sources/jaxws",
         '-p', 'com.example.service',
         "${projectDir}/src/main/resources/wsdl/service.wsdl"
}

compileJava.dependsOn wsimport
sourceSets.main.java.srcDir "${buildDir}/generated-sources/jaxws"

エラー 6: wsdlLocation のランタイムパス問題

生成されたコードには、ハードコードされたパスを含む @WebServiceClient アノテーションが含まれます:

@WebServiceClient(name = "OrderService",
    wsdlLocation = "file:/Users/dev/project/service.wsdl")
public class OrderService extends Service {

このパスは他のマシンや本番環境では動作しません。

修正方法: wsdlLocation を上書きする

wsimport -keep \
  -wsdllocation /wsdl/OrderService.wsdl \
  -d output/ \
  service.wsdl

WSDL をクラスパス (src/main/resources/wsdl/) に配置し、実行時にロードします:

URL wsdlUrl = OrderService.class.getResource("/wsdl/OrderService.wsdl");
OrderService service = new OrderService(wsdlUrl);
OrderServicePortType port = service.getOrderServicePort();

トラブルシューティングチェックリスト

症状原因修正方法
Two declarations cause collision要素名/型名の重複JAXB バインディングファイルで名前変更
undefined element s:schema.NET WSDL の固有仕様-extension フラグまたは WSDL 修正
Unsupported encodingレガシーエンコーディングiconv で UTF-8 に変換
ObjectFactory の同名クラス名前空間→パッケージ変換の衝突明示的パッケージバインディング
package javax.xml.ws does not existJava 11+ で JAX-WS 削除Jakarta 依存関係を追加
実行時に WSDL が見つからないハードコードされた wsdlLocation-wsdllocation フラグ
生成中にタイムアウトリモート WSDL に到達不可ローカルダウンロード + カタログ

SOAPless による解決

本記事で取り上げたすべてのエラーは、同じ根本的な問題に起因しています。WSDL ファイルからの Java クライアントコード生成は本質的に脆弱だということです。スキーマの変更は生成コードを壊し、名前衝突にはバインディングファイルが必要で、Java バージョンのアップグレードには依存関係の移行が伴います。

SOAPless はまったく異なるアプローチを取ります。クライアントコードを生成する代わりに、WSDL URL を SOAPless ダッシュボードに登録するだけで REST JSON エンドポイントが自動生成されます。アプリケーションは標準的な JSON を HTTP で送受信するだけです。生成スタブも JAXB バインディングも wsimport も不要です。JSON から SOAP XML への変換、名前空間管理、スキーマ解決はすべてサーバーサイドで処理されます。

SOAP 認証情報は AES-256-GCM 暗号化で保護され、登録されたすべてのサービスには OpenAPI 3.0 ドキュメントが自動生成されます。ダッシュボードからコードを書く前に直接オペレーションをテストできます。