奇妙な問題があります。
Wsimportを使用して、WSDLからals JAX-WSコードを生成しました(専用のEclipse Javaプロジェクト内)。これは、外部依存関係なしで(Eclipseで実行されて)JDK6で正常に動作します)
Apache CXFを使用した2番目のプロジェクトがあります。 1.)で説明したコードをこのプロジェクトにコピーすると、JDKが突然JAX-WSのもの(私が生成したファイル)ではなく、Apache CXFを実行します。
Apache CXFがJAX-WSを「実行」しないようにするにはどうすればよいですか。 (問題は、CXFがコードの実行に失敗することです...)。また、Apache CXFがこれらのクラスをどのように検出するかについても、完全には理解していません。登録しなかったのですか?
どうもありがとうございました!マーカス
Apache CXF(正確にはcxf-rt-frontend-jaxws-*.jar
)は、それ自体をJAX-WSプロバイダーとしてJVMに登録します。前述のJAR内には、次の内容の/META-INF/services/javax.xml.ws.spi.Provider
という名前のファイルがあります。
org.Apache.cxf.jaxws.spi.ProviderImpl
ここでjavax.xml.ws.spi.FactoryFinder#find
メソッドを見ると、JDKがCLASSPATHでjavax.xml.ws.spi.Provider
ファイルの存在を検索し、利用できない場合はデフォルトのSun実装にフォールバックすることがわかります。したがって、フォールバックを強制する2つのオプションがあります。
cLASSPATHからcxf-rt-frontend-jaxws-*.jar
を削除するか
または、CXFによって提供されるjavax.xml.ws.spi.Provider
ファイルをオーバーライドして、フォールバックの場所を指す
2番目のオプションは実際には少し簡単です。単に作成:
/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider
次の内容のファイル(Mavenを使用していると想定)。
org.Apache.cxf.jaxws.spi.ProviderImpl
javax.xml.ws.Endpoint#publish
でテスト済みです。
デフォルトの実装では、次のようにします。
com.Sun.xml.internal.ws.spi.ProviderImpl
/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider内
もう1つ試してみましたが、まったく機能しませんでした。CXFに設定されていない場合にCXFを設定するには、サービス内のデリゲートをオーバーライドするだけです。
try {
loc = this.getClass().getResource(wsdlResource);
QName qName = new QName( wsTargetNamespace, wsName );
service = new YourWS(loc, qName);
Field delegateField = Service.class.getDeclaredField("delegate"); //ALLOW CXF SPECIFIC SERVICE DELEGATE ONLY!
delegateField.setAccessible(true);
ServiceDelegate previousDelegate = (ServiceDelegate) delegateField.get(service);
if (!previousDelegate.getClass().getName().contains("cxf")) {
ServiceDelegate serviceDelegate = ((Provider) Class.forName("org.Apache.cxf.jaxws.spi.ProviderImpl").newInstance())
.createServiceDelegate(loc, qName, service.getClass());
log.info("The " + getClass().getSimpleName() + " delegate is changed from " + "[" + previousDelegate + "] to [" +
serviceDelegate +
"]");
delegateField.set(service, serviceDelegate);
}
port = service.getYourWSSoap();
標準の検索メカニズムはOSGi(*)ではうまく機能しないようです。
サービスに_javax.xml.ws.spi.Provider
_のCXF実装を強制的に取得させるには、2つの方法があります。
この質問に対するEpicPandaForceの回答で与えられたリフレクションによってdelegate
を設定するアプローチ( https://stackoverflow.com/a/31892305/109079 )
下位レベルのJaxWsProxyFactoryBean
を呼び出す;これは、Javaに含まれる_javax.xml.ws.spi.FactoryFinder
_へのすべての呼び出しを回避するようです。これは問題の根源です
以下は、プライベートフィールドを反射的に変更しないことを好むそれほど勇敢でないコーダーのための、後者の例です。
_JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getClientFactoryBean().getServiceFactory().setWsdlURL(WinRmService.WSDL_LOCATION);
factory.setServiceName(WinRmService.SERVICE);
factory.setEndpointName(WinRmService.WinRmPort);
// factory.setFeatures(...); // if required
Service winrm = factory.create(WinRm.class);
Client client = ClientProxy.getClient(winrm);
_
いくつかのメモ:
WSDLがクラスパス上のリソースである場合、より単純なfactory.setWsdlURL(String)
ではなく、上記のようにURL
を渡す必要があります(解決できない_bundle://...
_クラスパス項目のURLは避けてください)
機能(アドレッシングなど)には追加のバンドルが必要になる場合があります
(*)ほとんどのOSGiコンテナで検索メカニズムが機能しない理由については、Oracle JavaのFactoryFinder
:
_private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.Sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader";
private static boolean isOsgi() {
try {
Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
return true;
} catch (ClassNotFoundException ignored) {
}
return false;
}
_
OSGi = Glassfish?確かにうさんくさい!
同様の問題がありました。私の場合、JAX-WSのもの(Webサービスエンドポイントの作成など)にはorg.Apache.cxf.jaxws.spi.ProviderImpl
を、com.Sun.xml.internal.ws.spi.ProviderImpl
でのエンドポイントの公開にはcom.Sun.net.httpserver.HttpsServer
を使用する必要がありました。
javax.xml.ws.spi.Provider
を拡張する独自のプロバイダーを作成し、デフォルトのプロバイダーの代わりにそれを使用することで、これをなんとか解決しました。
package provider;
import Java.net.URL;
import Java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.Endpoint;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.Provider;
import javax.xml.ws.spi.ServiceDelegate;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import org.w3c.dom.Element;
public class MyProvider extends Provider
{
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public ServiceDelegate createServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class serviceClass)
{
try {
return ((Provider) Class.forName("org.Apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createServiceDelegate(wsdlDocumentLocation, serviceName, serviceClass.getClass());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public Endpoint createEndpoint(String bindingId, Object implementor)
{
try {
return ((Provider) Class.forName("com.Sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createEndpoint(bindingId, implementor);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public Endpoint createAndPublishEndpoint(String address, Object implementor)
{
try {
return ((Provider) Class.forName("com.Sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createAndPublishEndpoint(address, implementor);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public EndpointReference readEndpointReference(Source eprInfoset)
{
try {
return ((Provider) Class.forName("org.Apache.cxf.jaxws.spi.ProviderImpl").newInstance()).readEndpointReference(eprInfoset);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public <T> T getPort(EndpointReference endpointReference, Class<T> serviceEndpointInterface, WebServiceFeature... features)
{
try {
return ((Provider) Class.forName("org.Apache.cxf.jaxws.spi.ProviderImpl").newInstance()).getPort(endpointReference, serviceEndpointInterface, features);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public W3CEndpointReference createW3CEndpointReference(String address, QName serviceName, QName portName, List<Element> metadata, String wsdlDocumentLocation, List<Element> referenceParameters)
{
try {
return ((Provider) Class.forName("org.Apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createW3CEndpointReference(address, serviceName, portName, metadata, wsdlDocumentLocation,
referenceParameters);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
次に、単に作成します:
/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider
次の内容のファイル(Mavenを使用していると想定)。
package.MyProvider