如何将不继承 BindingProvider 的对象显式转换为 BindingProvider 对象?

knk*_*knk 2 java web-services jax-ws soap-client jakarta-ee

我有一个 Web 服务,我在其中使用客户端 API 中的服务接口对象操作 SOAP 标头。

我需要将端口对象类型转换为BindingProvider对象。但是我的端口对象没有直接继承那个类。那么JVM怎么可能不抱怨呢?

它也有效。ClassCastException 没有运行时错误

代码片段:

    public SearchDocument getSearchDocumentService(String wsdlUri, AuthBean auth){
    SearchDocument_Service serv = null;
    serv = SearchDocument_Service.getServiceInstance(wsdlUri);
    SearchDocument searchDoc = serv.getSearchDocument();

    populateAuthAndHandlerInfo((BindingProvider)searchDoc, auth);//how is it that jvm doesn't complain here
    return searchDoc;
    }

    private void populateAuthAndHandlerInfo(BindingProvider port, AuthBean auth) {
    Binding binding = port.getBinding();
              List<Handler> handlerList = binding.getHandlerChain();
              handlerList.add(new EDMSSoapAuthHandler());
              binding.setHandlerChain(handlerList);
        Map<String, Object> context = port.getRequestContext();
        context.put("clientAuthInfo", auth);
        }
Run Code Online (Sandbox Code Playgroud)

搜索文档.java:

    @WebService(name = "SearchDocument", targetNamespace = "http://services.abc.com/Technology/SearchDocument/service/v1")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public interface SearchDocument {


    /**
     * 
     * @param body
     * @return
     *     returns com.abc.technology.search.document.client.v1.SearchOnMetadataResponse
     * @throws AbcServiceException
     * @throws AbcInvalidMessageException
     * @throws AbcProducerApplicationException
     */
    @WebMethod(action = "http://services.abc.com/Technology/SearchDocument/service/v1/soap11/SearchDocument/searchOnMetadata")
    @WebResult(name = "SearchOnMetadataResponse", targetNamespace = "http://services.abc.com/Technology/SearchDocument/contract/v1", partName = "body")
    public SearchOnMetadataResponse searchOnMetadata(
        @WebParam(name = "SearchOnMetadata", targetNamespace = "http://services.abc.com/Technology/SearchDocument/contract/v1", partName = "body")
        SearchOnMetadataRequest body)
        throws AbcInvalidMessageException, AbcProducerApplicationException, AbcServiceException
    ;

}
Run Code Online (Sandbox Code Playgroud)

GPI*_*GPI 5

有几种方法可以回答您的问题。

从高层次的角度

但是我的端口对象没有直接继承那个类。那么JVM怎么可能不抱怨呢?

嗯...SearchDocument是一个接口。所以,当你打电话

SearchDocument searchDoc = serv.getSearchDocument();
Run Code Online (Sandbox Code Playgroud)

然后searchDoc是实现接口的给定类型的实例,但没有指定这个具体类是什么。它可以是任何东西,包括同时实现SearchDocument和的具体类BindingProvider,因为两者都是接口,任何给定的类型都可以同时实现多个接口。所以这一定是这里发生的事情,对吧?

来自 JAX WS 规范

查看 JAXWS 规范可能会进一步启发您。您可以在https://jcp.org/en/jsr/detail?id=224下载它,但我会在第 4.2.3 章为您引用一些要点:

代理在运行时提供对服务端点接口的访问,而无需静态生成存根类。有关 JDK 支持的动态代理的更多信息,请参阅 java.lang.reflect.Proxy

...

一致性(实现 BindingProvider):代理的实例必须实现 javax-.xml.ws.BindingProvider

...

使用Service 实例的 getPort 方法创建代理: T getPort(Class sei) 返回指定 SEI 的代理

现在很容易将这些部分重新组合在一起。

什么是java.lang.reflect.Proxy东西。

在 JVM 中,有一个用于创建代理对象的 API。Proxy对象(实例)是 JVM 中一种特殊的野兽,可以在运行时动态创建,并且可以使每个代理符合任何给定的接口。这就像Class在运行时创建一个,而不是在编译时,并且不必编写它的 java 源文件。当然,有各种限制,但也有很多可能性。

一个是说给JVM:“哎,给我一个Proxy对象,它实现的接口SearchDocument,并BindingProvider在同一时间”。JVM 也是如此。它返回一个对象,它的具体类是Proxy(通常是 Proxy$x,其中 x 是一个数字),并且是专门为实现这两个接口而设计的。

如果你想知道这在这一点上是否有任何用处,那么不,它不是,因为创建一个没有实现的类型是毫无意义的。但是有一种方法可以通过所谓的InvocationHandler你编程的方式来提供实现和行为(具体如何是另一个讨论)。

所以,在这一点上,我们从规范得到的是,如果我们所说getPort的一个javax.xml.ws.Service,然后,其结果必然是一个JDK代理,那也必须实现BindingProvider

回到你的案例

我敢打赌,这正是您调用 : 时发生的情况SearchDocument_Service,它最终调用一个getPort方法,并确保结果实现BindingProvider,因为 JAXWS 说它必须这样做,以及您的SearchDocument“业务”接口,因为它对你。