私はSOAPサービスをバグ報告など)に利用するファットクライアントを書いています。
JAX-WSは正常に動作しますが、デフォルトでは(少なくともnetbeansでは)サービスが初期化されるたびにリモートサーバーからWSDLを取得します。これはバージョン管理のサポートなどを提供するのに役立つと思いますが、それは私が望むものではありません。
wsdllocation
argをwsimportに追加して、生成されたクラスがローカルリソースを指すようにしました。次のスニペットは、ApplicationService.JavaからのWSDLリソースのURLロードです。
baseUrl = net.example.ApplicationService.class.getResource(".");
url = new URL(baseUrl, "service.wsdl");
Net/example/resourcesパッケージのjar内に保存されたリソースを指す問題はないはずです。jar自体は期待どおりに構築されます。ただし、サービスはロードされません...具体的には、ApplicationService.getPort()を呼び出すとNullPointerExceptionが発生します。
これは可能ですか?それともただのガチョウの追跡?
はい、これは、WS-A関連クラスであるjavax.xml.ws.EndpointReferenceを介してクライアントを作成するときに行ったため、最も確実に可能です。 WSDLへのクラスパス参照をWS-A EndPointReferenceに追加し、JAX-WSのMetro実装はそれを正常にロードしました。 WSDLをWS-A EndPointReferenceからロードする場合でも、ファイルまたはhttp URLからロードする場合でも、JAX-WS実装では、URLを解決するのと同じWSDL解析コードを使用する必要があります。
あなたにとって最良のアプローチは、おそらく次のようなことをすることです:
URL wsdlUrl = MyClass.class.getResource(
"/class/path/to/wsdl/yourWSDL.wsdl");
Service yourService= Service.create(
wsdlUrl,
...);
...は、WSDL内のWSDLサービスのQNameを表します。ここで覚えておくべき重要なことは、WSDLが完全で有効である必要があるということです。これは、WSDLがXSDファイルまたは他のWSDLをインポートする場合、URLが正しい必要があることを意味します。インポートしたWSDLとXSDをWSDLファイルと同じJARに含めた場合、インポートに相対URLを使用し、すべてのインポートを同じJARファイルに保持する必要があります。 JAR URLハンドラーは、相対URLをクラスパスに対してではなく、JARファイル内の相対として扱います。そのため、カスタムURLハンドラーと独自のプレフィックスを実装しない限り、JAR全体で実行されるWSDLのインポートはできませんインポートのクラスパスベースの解決。 WSDLが外部リソースをインポートする場合、それは問題ありませんが、それらのリソースが移動した場合は、メンテナンスの問題にサインアップします。クラスパスからWSDLの静的コピーを使用しても、WSDL、Webサービス、およびJAX-WSの精神に反しますが、必要な場合があります。
最後に、静的なWSDLを埋め込む場合は、少なくともテストと展開の目的でサービスエンドポイントを構成可能にすることをお勧めします。 Webサービスクライアントのエンドポイントを再構成するコードは次のとおりです。
YourClientInterface client = yourService.getPort(
new QName("...", "..."),
YourClientInterface.class);
BindingProvider bp = (BindingProvider) client;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://localhost:8080/yourServiceEndpoint");
少なくとも最近のJAX-WSでは、スキーマカタログやプログラムによるwsdlの場所設定を行う必要はありません[〜#〜] if [〜#〜] WSDLをJARに入れてから設定wsimport wsdlLocation
をJAR内のWSDLの相対リソースパスに。つまり、JAX-WSはJavaの組み込みClass.getResource
WSDLをロードします。
Mavenを使用している場合:
<plugin>
<groupId>org.jvnet.jax-ws-commons</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<!-- Following configuration will invoke wsimport once for each wsdl. -->
<configuration>
<!--- VERY IMPORTANT THAT THE PATH START WITH '/' -->
<wsdlLocation>/com/adamgent/ws/blah.wsdl</wsdlLocation>
<wsdlDirectory>${basedir}/src/main/resources/com/adamgent/ws</wsdlDirectory>
<wsdlFiles><wsdlFile>blah.wsdl</wsdlFile></wsdlFiles>
</configuration>
</execution>
</executions>
</plugin>
上の例では、Mavenプロジェクトレイアウトを使用してWSDLをここに配置しますsrc/main/resources/com/adamgent/ws
。
WSDLが次のようにMavenのJARに含まれていることを確認します。
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources> ....
これで、wsimportが生成したコードとWSDLは自己完結型のJARになりました。サービスを使用するには、WSDLの場所を設定する必要はなく、次のように簡単です。
BlahService myService = new BlayService_Service().getBlahServicePort();
これをANTのwsimportにマッピングするのは簡単です。
少し遅かったかもしれませんが、この問題を解決するための非常に簡単な解決策を見つけましたが、これにはServiceクラスの生成コードの変更が含まれていました。
Serviceクラスの次の行
baseUrl = net.example.ApplicationService.class.getResource(".");
に変更されます
baseUrl = net.example.ApplicationService.class.getResource("");
jARにパックされたWSDLでも正常に機能します。いずれの場合でもgetResource()の正確な想定動作についてはわかりませんが、複数のOSおよびJavaバージョン。
説明するのはJAX-WSのバグです。 JAX_WS-888-カスタムwsdlLocationのURLを解決するための間違ったコード 。
これはV2.2で修正されたため、作成中にwsdlLocation
を設定するだけで動作するはずです。
他の答えは
new Service(wsdllocation, servicename );
サービスオブジェクトを取得します。
これが私が問題を解決した方法です。
クラスパスに「。」がある場合その中で、Class.getResource( "。")は、Javaコマンドを実行したディレクトリのURLを返します。それ以外の場合は、nullを返します。それに応じてwsdllocationを調整します。
ここでクライアントjarを作成する前に、WSDLの場所を置き換えました。
<copy todir="@{dest-dir}/@{dir-package}" verbose="@{verbose}">
<fileset dir="@{dir-wsdl}" includes="*.wsdl,*.xsd" />
</copy>
<echo message="Replacing Service to point to correct WSDL path..." />
<replaceregexp match="new URL(.*)" replace='Class.class.getResource("@{name-wsdl}");' flags="gm">
<fileset dir="@{source-dest-dir}">
<include name="@{dir-package}/*Service.Java" />
</fileset>
</replaceregexp>
<replaceregexp match="catch (.*)" replace='catch (Exception ex) {' flags="gm">
<fileset dir="@{source-dest-dir}">
<include name="@{dir-package}/*Service.Java" />
</fileset>
</replaceregexp>
私は同じ問題につまずいた。 JAXWS生成クライアントコードはMyService.class.getResource(".")
トリックを使用してwsdlファイルをロードしますが、テスト後、クラスファイルがfilesytemのディレクトリにある場合にのみ機能するようです。クラスファイルがJARにある場合、この呼び出しはURLに対してnullを返します。
次のようにURLを作成すると、JDKのバグのように聞こえます。
final URL url = new URL( MyService.class.getResource( MyService.class.getSimpleName() + ".class"), "myservice.wsdl");
クラスとwsdlがjarにバンドルされている場合にも機能します。
私はほとんどの人が実際に瓶にバンドルすると思います!
これが私のハックな回避策です。
JarからWSDLを解凍し、jarの近くのファイルに書き込みます。
File wsdl = new File("../lib/service.wsdl");
InputStream source = getClass().getResource("resources/service.wsdl").openStream();
FileOutputStream out = new FileOutputStream(wsdl);
byte[] buffer = new byte[512];
int read;
while((read = source.read(buffer)) >= 0) {
out.write(buffer, 0, read);
}
次に、サービスクラスがfile:../lib/service.wsdl
を指すようにします。
これは機能しますが、誰かがもっとエレガントなソリューションを見せてくれれば幸いです。
ここに私のために働くものがあります(特に、httpおよびhttpsを介して)。 Apache CXF 3.1.1で作成されたクラスで動作するOracle JDK 1.8.0_51のJAX-WSの場合。
リモートWSDLは、どの場合でも最初の呼び出しでのみ取得されることに注意してください。使用パターン(長時間実行されるプログラム)によっては、これは完全に受け入れられる場合があります。
基礎:
wget --output-document=wsdl_raw.xml $WSDL_URL
xmllint --format wsdl_raw.xml > wsdl.xml
が必要な場合があります./cxf/bin/wsdl2Java -d output/ -client -validate wsdl.xml
を使用してクライアントクラスを生成し、プロジェクトにインポートしますhttpとhttpsの両方のサービス定義がWSDLファイルに存在することを確認します。私の場合、プロバイダーにはhttpsに対するものはありませんでしたが(httpsトラフィックを受け入れました)、手動で追加する必要がありました。これらの行に沿った何かがWSDLにあるはずです:
<wsdl:service name="fooservice">
<wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort">
<soap:address location="http://ws.example.com/a/b/FooBarWebService"/>
</wsdl:port>
</wsdl:service>
<wsdl:service name="fooservice-secured">
<wsdl:port binding="tns:fooserviceSoapBinding" name="FooBarWebServicePort">
<soap:address location="https://ws.example.com/a/b/FooBarWebService"/>
</wsdl:port>
</wsdl:service>
CXFは、適切なコンストラクターを使用して、たとえばFooservice
と呼ばれるjavax.xml.ws.Service
を実装するクラスを生成する必要があります。
public class Fooservice extends Service {
public Fooservice(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public Fooservice(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public Fooservice() {
super(WSDL_LOCATION, SERVICE);
}
...etc...
コードのどこか(ここでは読みやすいようにいくつかのGroovy)で、上記のService
インスタンスを初期化し、ポートを呼び出します。ここでは、secure
というフラグに応じて、httpsまたはhttpを使用します。
static final String NAMESPACE = 'com.example.ws.a.b'
static final QName SERVICE_NAME_HTTP = new QName(NAMESPACE, 'fooservice')
static final QName SERVICE_NAME_HTTPS = new QName(NAMESPACE, 'fooservice-secured')
Fooservice wsService
File wsdlfile = new File('/somewhere/on/disk/wsdl.xml')
// If the file is missing there will be an exception at connect
// time from Sun.net.www.protocol.file.FileURLConnection.connect
// It should be possible to denote a resource on the classpath
// instead of a file-on-disk. Not sure how, maybe by adding a handler
// for a 'resource:' URL scheme?
URI wsdlLocationUri = Java.nio.file.Paths(wsdlfile.getCanonicalPath()).toUri()
if (secure) {
wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTPS)
}
else {
wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP)
}
SomeServicePort port = wsService.getSomeServicePort()
port.doStuff()
サービスの呼び出しに使用される接続とは別の接続でWSDLをダウンロードする別の方法(トラフィックを監視するにはtcpdump -n -nn -s0 -A -i eth0 'tcp port 80'
を使用)は、次のようにします。
URI wsdlLocationUri
if (secure) {
wsdlLocationUri = new URI('https://ws.example.com/a/b/FooBarWebService?wsdl')
}
else {
wsdlLocationUri = new URI('http://ws.example.com/a/b/FooBarWebService?wsdl')
}
Fooservice wsService = new Fooservice(wsdlLocationUri.toURL(), SERVICE_NAME_HTTP)
SomeServicePort port = wsService.getSomeServicePort()
port.doStuff()
wsdlLocationUri
がSERVICE_NAME_HTTP
で初期化されているという事実にもかかわらず、wsService
がhttpsを指定する場合、これは実際にhttpsを適切に使用することに注意してください。 (理由はわかりません-サービスは、WSDLリソースの取得に使用されるスキームを使用しますか?)
そしてそれはそれについてです。
接続をデバッグするには、次を渡します。
-Dcom.Sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
-Dcom.Sun.xml.internal.ws.transport.http.HttpAdapter.dump=true
コマンドラインでJVMに。これにより、http接続コードからstdoutに情報が書き込まれます(残念ながら、Java.util.logging
ではありません。Oracle、お願いします!)。
私の解決策は、生成されたサービスを変更することでした。ヘッダーアノテーションのwsdlLocationを変更する必要があり、インスタンス化ブロックは次のようになります。
static {
URL url = null;
url = com.ups.wsdl.xoltws.ship.v1.ShipService.class.getResource("Ship.wsdl");
SHIPSERVICE_WSDL_LOCATION = url;
}
ShipServiceクラスの隣のbinディレクトリにwsdlファイルを配置します
複雑にする必要はありません。jarクラスローダーを使用するだけです
ClassLoader cl = SomeServiceImplService.class.getClassLoader();
SERVICE_WSDL_LOCATION = cl.getResource("META-INF/wsdls/service.wsdl");
それを試してみてください!
いくつかの操作で動作するようにすることはできますが、notを実行し、現在の方法を維持することをお勧めします。
Webサービスエンドポイントプロバイダーは、契約の一部としてWSDLを提供する必要があります。生成するコードは、サーバー自体からWSDLからプルする必要があります。
WebSphereでの展開時に、展開UIからエンドポイントを他のエンドポイントに変更できます。他のアプリケーションサーバーでは、ベンダー固有のバインディングXMLを見つけてそれを実行する必要があります。
初期化時にのみ発生するため、アプリケーション全体への影響はごくわずかです。