Supplying a different version of JAXB for JAX
I have a third party jar that ships with a jaxb-impl.jar and includes it in its manifest classpath. The problem is, it seems as though supplying your own version of JAXB (regardless of which version it may be) seems to break the SoapFaultBuilder in JAX-WS.
According to the Unofficial JAXB Guide, it seems as though Sun deliberately changed the package name when it folded JAXB into the JDK in order to avoid conflicts with the stand-alone version. However, the SoapFaultBuilder (part of JAX-WS I believe) that ships with the JDK is explicitly dependent on the new, internal package name. This causes it to fail when building a fault message if you've added a stand-alone JAXB jar (even if it is the same version number of JAXB).
Here is my small test case: I make a trivial Web Service:
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);
}
And an implementation that simply throws an exception. (Since the problem only occurs in the 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);
}
}
And a class to publish the web service:
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());
}
}
I run the HelloWorldPublisher, and then run this client against it:
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"));
}
}
This correctly spits out the exception that was thrown by the Web Service. However, when I add any version of jaxb-impl.jar, whether on the classpath or in the endorsed lib, I get this stack trace:
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
The exception occurs because com.sun.xml.bind.v2.runtime.JAXBContextImpl from my jaxb-impl extends com.sun.xml.bind.api.JAXBRIContext instead of com.sun.xml.internal.bind.api.JAXBRIContext (note the missing 'internal' sub-package in the package hierarchy).
Also according to the Unofficial JAXB Guide, they say you need to use endorsed lib in order to correctly override the version of JAXB. As it turns out though, SOAPFaultBuilder uses JAXBContext.newInstance() to search the classpath for a file named /META-INF/services/javax.xml.bind.JAXBContext
, then manually load (and reflexively create) a JAXBContext based on the class name specified in the file. So it doesn't matter - classpath or endorsed lib gives you the same behavior.
One workaround is to add -Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory
to the command line, which causes JAXBContext.newInstance() to ignore the /META-INF/services/javax.xml.bind.JAXBContext
file on the classpath and manually specifies the built-in version of JAXB. The other workaround is to simply not specify your own JAXB and use the version built into the JDK, but it seems from the Unofficial JAXB Guide, that Sun designed this system to be able to handle supplying your own JAXB implementation. Has anyone been able to successfully supply a version of JAXB and still be able to successfully capture fault messages? (Everything runs fine for me as long as there are no faults generated by the Web Service).
我被困在这个问题上,但能够通过设置系统属性来使用此论坛问答中列出的“解决方法”:
System.setProperty("javax.xml.bind.JAXBContext",
"com.sun.xml.internal.bind.v2.ContextFactory");
The crux of this issue is there is a change in the JAXB API , the runtime implementation you are attempting to use does not match the version of the JAXB API bundled with the JDK.
In order to use a different version, you should copy coresponding versions of jaxb-api.jar and jaxws-api.jar into an endorsed lib (eg %JAVA_HOME%libendorsed
).
A complete list of options is given in section 7.1.2 of the Unofficial JAXB Guide
It is a mistake to copy the implementation jars (eg jaxb-impl.jar) into endorsed lib, these should simply be on your classpath.
Also note that you can get into trouble if you attempt to use a newer version of jaxb without also including a compatible version of jaxws. This is because the old jaxws attempts to reference the old jaxb, so if you're changing one make sure you do both. (Stack-trace in package com.sun.xml.internal.ws
implicates an old jax-ws implementation. Even the latest release of Java still ships with old version 1 jaxb and jaxws apis).
another possible solution without modifying the system properties is described at API docu
https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/xml/bind/JAXBContext.html
you can place a jaxb.properties file inside of the package of your model class.
javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory
链接地址: http://www.djcxy.com/p/41854.html
上一篇: MOXy @XmlPath被忽略
下一篇: 为JAX提供不同版本的JAXB