web-dev-qa-db-ja.com

JAX-WS = Apache CXFがインストールされると、デフォルトのJDK JAX-WS実装を「盗む」ため、どのように解決しますか?

奇妙な問題があります。

  1. Wsimportを使用して、WSDLからals JAX-WSコードを生成しました(専用のEclipse Javaプロジェクト内)。これは、外部依存関係なしで(Eclipseで実行されて)JDK6で正常に動作します)

  2. Apache CXFを使用した2番目のプロジェクトがあります。 1.)で説明したコードをこのプロジェクトにコピーすると、JDKが突然JAX-WSのもの(私が生成したファイル)ではなく、Apache CXFを実行します。

Apache CXFがJAX-WSを「実行」しないようにするにはどうすればよいですか。 (問題は、CXFがコードの実行に失敗することです...)。また、Apache CXFがこれらのクラスをどのように検出するかについても、完全には理解していません。登録しなかったのですか?

どうもありがとうございました!マーカス

33
Markus

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でテスト済みです。

59

デフォルトの実装では、次のようにします。

com.Sun.xml.internal.ws.spi.ProviderImpl

/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider内

16
Ken Larson

もう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();
7
EpicPandaForce

標準の検索メカニズムは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?確かにうさんくさい!

3
Partly Cloudy

同様の問題がありました。私の場合、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
1