繁体   English   中英

在Java 1.6中为JAX-WS提供不同版本的JAXB

[英]Supplying a different version of JAXB for JAX-WS in Java 1.6

我有一个第三方jar,它附带一个jaxb-impl.jar并将其包含在其manifest类路径中。 问题是,似乎提供自己的JAXB版本(无论它是哪个版本)似乎打破了JAX-WS中的SoapFaultBuilder。

根据非官方的JAXB指南 ,似乎Sun在将JAXB折叠到JDK中时故意更改了包名称,以避免与独立版本冲突。 但是,随JDK一起提供的SoapFaultBuilder(我相信JAX-WS的一部分)明确依赖于新的内部包名。 如果您添加了一个独立的JAXB jar(即使它与JAXB的版本相同),这会在构建错误消息时导致失败。

这是我的小测试案例:我制作一个简单的Web服务:

package wstest;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld{

    @WebMethod String getHelloWorldAsString(String name);

}

一个简单抛出异常的实现。 (因为问题只出现在SOAPFaultBuilder中):

package wstest;

import javax.jws.WebService;

//Service Implementation
@WebService(endpointInterface = "wstest.HelloWorld")
public class HelloWorldImpl implements HelloWorld{

    @Override
    public String getHelloWorldAsString(String name) {
        //return "Hello World JAX-WS " + name;
        throw new RuntimeException("Exception for: " + name);
    }

}

还有一个发布Web服务的类:

package wstest;

import javax.xml.ws.Endpoint;

//Endpoint publisher
public class HelloWorldPublisher{

    public static void main(String[] args) {
       Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
    }

}

我运行HelloWorldPublisher,然后针对它运行此客户端:

package wstest;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class HelloWorldClient{

    public static void main(String[] args) throws Exception {

    URL url = new URL("http://localhost:9999/ws/hello?wsdl");

        //1st argument service URI, refer to wsdl document above
    //2nd argument is service name, refer to wsdl document above
        QName qname = new QName("http://wstest/", "HelloWorldImplService");

        Service service = Service.create(url, qname);

        HelloWorld hello = service.getPort(HelloWorld.class);

        System.out.println(hello.getHelloWorldAsString("Matt"));

    }

}

这正确地吐出了Web服务引发的异常。 但是,当我添加任何版本的jaxb-impl.jar时,无论是在类路径还是在支持的lib中,我都会得到这个堆栈跟踪:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:107)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
    at $Proxy19.getHelloWorldAsString(Unknown Source)
    at wstest.HelloWorldClient.main(HelloWorldClient.java:21)
Caused by: java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext
    at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.<clinit>(SOAPFaultBuilder.java:533)
    ... 5 more

发生异常的原因是我的jaxb-impl中的com.sun.xml.bind.v2.runtime.JAXBContextImpl扩展了com.sun.xml.bind.api.JAXBRIContext而不是com.sun.xml.internal.bind.api.JAXBRIContext(请注意包层次结构中缺少的“内部”子包。

另外根据非官方JAXB指南 ,他们说你需要使用支持的lib才能正确覆盖JAXB的版本。 事实证明,SOAPFaultBuilder使用JAXBContext.newInstance()在类路径中搜索名为/META-INF/services/javax.xml.bind.JAXBContext的文件,然后根据类手动加载(并反复创建)JAXBContext文件中指定的名称。 因此无关紧要 - classpath或endorsed lib为您提供相同的行为。

一种解决方法是将-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory添加到命令行,这会导致JAXBContext.newInstance()忽略/META-INF/services/javax.xml.bind.JAXBContext类路径上的/META-INF/services/javax.xml.bind.JAXBContext文件,并手动指定JAXB的内置版本。 另一种解决方法是简单地不指定您自己的JAXB并使用JDK中内置的版本,但是从非官方JAXB指南中可以看出,Sun设计此系统是为了能够处理提供您自己的JAXB实现。 有没有人能够成功提供JAXB版本并仍然能够成功捕获故障消息? (只要没有Web服务生成的错误,一切都运行正常)。

我被困在这个问题但是能够通过设置系统属性来使用此 论坛 问答中列出的“解决方法”:

System.setProperty("javax.xml.bind.JAXBContext", 
                   "com.sun.xml.internal.bind.v2.ContextFactory"); 

这个问题的关键是JAXB API发生了变化,您尝试使用的运行时实现与JDK捆绑的JAXB API版本不匹配。

为了使用不同的版本,您应该将相应版本的jaxb-api.jarjaxws-api.jar复制到一个支持的lib(例如%JAVA_HOME%\\lib\\endorsed )。

完整的选项列表在非官方JAXB指南的7.1.2节中给出

将实现jar(例如jaxb-impl.jar)复制到endorsed lib中是错误的,这些应该只是在你的类路径上。

另请注意,如果您尝试使用较新版本的jaxb而不包含兼容版本的jaxws,则可能会遇到麻烦。 这是因为旧的jaxws试图引用旧的jaxb,所以如果你要更改一个,请确保你同时执行这两个操作。 com.sun.xml.internal.ws包中的堆栈跟踪暗示了一个旧的jax-ws实现。即使最新版本的Java仍然附带旧版本1 jaxb和jaxws apis)。

API文档中描述了另一种可能的解决方案,无需修改系统属性

https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/xml/bind/JAXBContext.html

您可以将jaxb.properties文件放在模型类的包中。

javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM