为JAX提供不同版本的JAXB
我有一个第三方jar,它附带一个jaxb-impl.jar并将它包含在其清单类路径中。 问题是,似乎提供您自己的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时,无论是在classpath还是在认可的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(注意包层次结构中缺少的'internal'子包)。
另外根据非官方的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
文件并手动指定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.jar和jaxws-api.jar的相应版本复制到背书库(例如%JAVA_HOME%libendorsed
)中。
非官方JAXB指南第7.1.2节给出了完整的选项列表
将实现jar(例如jaxb-impl.jar)复制到背书的lib中是错误的,它们应该只在你的类路径上。
另外请注意,如果您尝试使用较新版本的jaxb而不包含兼容版本的jaxws,则可能会遇到麻烦。 这是因为旧的jaxws试图引用旧的jaxb,所以如果你改变了一个,确保你做到了。 (包com.sun.xml.internal.ws
Stack-trace包含旧的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
链接地址: http://www.djcxy.com/p/41853.html
上一篇: Supplying a different version of JAXB for JAX
下一篇: Does Samsung not respect orientation in android manifest?