如何将不属于 BindingProvider 子类的 object 显式转换为 BindingProvider object?

How is an object which does not subclass BindingProvider be casted explicitly into a BindingProvider object?

我有一个 Web 服务,我在其中使用客户端 API 中的服务接口 object 来操作 SOAP headers。

我需要将端口 object 类型转换为 BindingProvider object。但是我的端口object并没有直接subclass那个class。那么 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);
        }

SearchDocument.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
    ;

}

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

从高层次的角度来看

But my port object does not directly subclass that class. So how is it possible the JVM doesn't complain ?

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

SearchDocument searchDoc = serv.getSearchDocument();

那么 searchDoc 是实现该接口的给定类型的实例,但没有指定具体的 class 是什么。它可以是任何东西,包括实现 SearchDocumentBindingProvider 的具体 class,因为两者都是接口,任何给定类型都可以同时自由实现多个接口。 所以这种一定是这里发生的事情吧?

来自 JAX WS 规范

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

Proxies provide access to service endpoint interfaces at runtime without requiring static generation of a stubclass. See java.lang.reflect.Proxy for more information on dynamic proxies as supported by the JDK

...

Conformance (Implementing BindingProvider): An instance of a proxy MUST implement javax-.xml.ws.BindingProvider

...

A proxy is created using the getPort methods of a Service instance: T getPort(Class sei) Returns a proxy for the specified SEI

现在很容易将各个部分重新组合在一起。

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

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

一个是对 JVM 说:"hey, give me a Proxy object that implements the interfaces SearchDocumentand BindingProvider at the same time"。 JVM 也是如此。它返回一个对象,其具体 class 是 Proxy(通常是 Proxy$x,其中 x 是一个数字),并且是专门为实现这两个接口而设计的。

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

所以,在这一点上,我们从规范中得到的是,如果我们在 javax.xml.ws.Service 上调用 getPort,那么结果必须是一个 JDK 代理,它必须还实施 BindingProvider.

回到你的案例

我敢打赌,当您调用 SearchDocument_Service 时,它最终会调用 getPort 方法,并确保结果实现 BindingProvider,因为 JAXWS说它必须这样做,还有你的 SearchDocument "business" 界面,因为它对你有用。