简体   繁体   English

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

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

I have a third party jar that ships with a jaxb-impl.jar and includes it in its manifest classpath. 我有一个第三方jar,它附带一个jaxb-impl.jar并将其包含在其manifest类路径中。 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. 问题是,似乎提供自己的JAXB版本(无论它是哪个版本)似乎打破了JAX-WS中的SoapFaultBuilder。

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. 根据非官方的JAXB指南 ,似乎Sun在将JAXB折叠到JDK中时故意更改了包名称,以避免与独立版本冲突。 However, the SoapFaultBuilder (part of JAX-WS I believe) that ships with the JDK is explicitly dependent on the new, internal package name. 但是,随JDK一起提供的SoapFaultBuilder(我相信JAX-WS的一部分)明确依赖于新的内部包名。 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). 如果您添加了一个独立的JAXB jar(即使它与JAXB的版本相同),这会在构建错误消息时导致失败。

Here is my small test case: I make a trivial Web Service: 这是我的小测试案例:我制作一个简单的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);

}

And an implementation that simply throws an exception. 一个简单抛出异常的实现。 (Since the problem only occurs in the SOAPFaultBuilder): (因为问题只出现在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: 还有一个发布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());
    }

}

I run the HelloWorldPublisher, and then run this client against it: 我运行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"));

    }

}

This correctly spits out the exception that was thrown by the Web Service. 这正确地吐出了Web服务引发的异常。 However, when I add any version of jaxb-impl.jar, whether on the classpath or in the endorsed lib, I get this stack trace: 但是,当我添加任何版本的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

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

Also according to the Unofficial JAXB Guide , they say you need to use endorsed lib in order to correctly override the version of JAXB. 另外根据非官方JAXB指南 ,他们说你需要使用支持的lib才能正确覆盖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. 事实证明,SOAPFaultBuilder使用JAXBContext.newInstance()在类路径中搜索名为/META-INF/services/javax.xml.bind.JAXBContext的文件,然后根据类手动加载(并反复创建)JAXBContext文件中指定的名称。 So it doesn't matter - classpath or endorsed lib gives you the same behavior. 因此无关紧要 - classpath或endorsed lib为您提供相同的行为。

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. 一种解决方法是将-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的内置版本。 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. 另一种解决方法是简单地不指定您自己的JAXB并使用JDK中内置的版本,但是从非官方JAXB指南中可以看出,Sun设计此系统是为了能够处理提供您自己的JAXB实现。 Has anyone been able to successfully supply a version of JAXB and still be able to successfully capture fault messages? 有没有人能够成功提供JAXB版本并仍然能够成功捕获故障消息? (Everything runs fine for me as long as there are no faults generated by the Web Service). (只要没有Web服务生成的错误,一切都运行正常)。

I was stuck on this problem but was able to use the "work around" listed in this forum Q&A by setting a system property like so: 我被困在这个问题但是能够通过设置系统属性来使用此 论坛 问答中列出的“解决方法”:

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

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

A complete list of options is given in section 7.1.2 of the Unofficial JAXB Guide 完整的选项列表在非官方JAXB指南的7.1.2节中给出

It is a mistake to copy the implementation jars (eg jaxb-impl.jar) into endorsed lib, these should simply be on your classpath. 将实现jar(例如jaxb-impl.jar)复制到endorsed lib中是错误的,这些应该只是在你的类路径上。

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. 另请注意,如果您尝试使用较新版本的jaxb而不包含兼容版本的jaxws,则可能会遇到麻烦。 This is because the old jaxws attempts to reference the old jaxb, so if you're changing one make sure you do both. 这是因为旧的jaxws试图引用旧的jaxb,所以如果你要更改一个,请确保你同时执行这两个操作。 (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). com.sun.xml.internal.ws包中的堆栈跟踪暗示了一个旧的jax-ws实现。即使最新版本的Java仍然附带旧版本1 jaxb和jaxws apis)。

another possible solution without modifying the system properties is described at API docu API文档中描述了另一种可能的解决方案,无需修改系统属性

https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/xml/bind/JAXBContext.html 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. 您可以将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