【问题标题】:ClassCastException with JAXB - Websphere jar vs applicationl jarClassCastException with JAXB - Websphere jar vs applicationl jar
【发布时间】:2016-05-05 14:58:58
【问题描述】:

我在尝试将 Java 对象编组为字符串时遇到类转换异常。我在我的 lib 文件夹中包含了 JAXB-2.1 jar。在部署到 WAS 时,我已将类加载器策略更改为最后一个父级,以便我的本地库中的 jar 将首先被拾取。但这仍然会引发带有以下消息的 classcast 异常。这个错误的原因是什么?

javax.xml.bind.JAXBException: ClassCastException: attempting to cast jar:file:/opt/was7/base/crm/java/jre/lib/rt.jar!/javax/xml/bind/JAXBContext.class to wsjar:file:/prod/wesadm/wes/was7/base/profiles/sadasd/installedApps/asdadad/myapp.ear/myapp_war.war/WEB-INF/lib/jaxb-api-2.1.jar!/javax/xml/bind/JAXBContext.class.  Please make sure that you are specifying the proper ClassLoader.
        at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:96)
        at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:214)
        at javax.xml.bind.ContextFinder.find(ContextFinder.java:372)
        at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
        at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
        at com.my.MyClass.convertObjectToXML()

这是 convertObjectToXML() 方法。

private <T> String convertObjectToXMLString(T obj) throws JAXBException {
        JAXBContext jaxbContext = JAXBContext.newInstance(obj.getClass());
        Marshaller marshaller = jaxbContext.createMarshaller();

        StringWriter sw = new StringWriter();
        marshaller.marshal(obj, sw);

        return sw.toString();

    }

这个逻辑在部署到 Tomcat 时可以正常工作。即使我最后提到了类加载器作为父级,我也无法弄清楚为什么要拾取 WAS jar。

【问题讨论】:

  • 您是否检查了服务器中的策略,如果策略是单一的,那么服务器级模式将被强制应用于所有应用程序,如果策略是多个,那么每个应用程序将有自己的模式 @987654321 @

标签: java tomcat jaxb websphere ibm-was


【解决方案1】:

您似乎将 JAXB api jar 与您的应用程序捆绑在一起。从您的应用程序中删除它们,它将起作用。这些 jars 已经与 WebSphere 捆绑在一起(实际上它们是 JRE 的一部分),它会导致类加载器异常,因为存在相同类的两个版本

【讨论】:

  • 这可能会解决问题,但它并不能真正解释为什么应用程序中的 JAXB API 无法从应用程序加载相应的 JAXB 实现。也许 OP 在应用程序中只有 API JAR...
  • JAXB 类是 JRE 的一部分,因此像这样覆盖 JRE 类是个坏主意。覆盖 JRE 类的官方方法是将 jar 放在 \lib\endorsed 文件夹中。您可以(待验证)通过设置“javax.xml.bind.JAXBContext”属性覆盖这些类,在您的应用中包含 jar 并反转您的应用的类加载顺序(父优先) .但我不确定这会起作用..为什么它在 Tomcat 中起作用而不在 WAS 中起作用?这是由于在两种产品中处理类加载的方式不同
  • WebSphere 不支持覆盖 JVM 中包含的 JAXB API,也不支持设置 javax.xml.bind.JAXBContext。这是因为产品本身在内部使用 JAXB,覆盖默认值可能会导致问题。据推测,Tomcat 本身并不使用 JAXB。归根结底,覆盖 JAXB 是脆弱的,最好完全避免它。
【解决方案2】:

在将应用程序迁移到 Websphere 9 时,我遇到了异常。

java.lang.Exception: javax.xml.bind.JAXBException: ClassCastException: attempting to cast jar:file:/D:/WebSphere/AppServer/endorsed_apis/jaxb-api.jar!/javax/xml/bind/JAXBContext.class to wsjar:file:/D:/sites/XXXX.ear/Web.war/WEB-INF/lib/jaxb-api-2.2.10.jar!/javax/xml/bind/JAXBContext.class.  Please make sure that you are specifying the proper ClassLoader.    

我现在从属于 IBM jdk 的应用程序中排除了所有 jar 引用。例如stax-api

    <dependency>
        <groupId>org.apache.xmlbeans</groupId>
        <artifactId>xmlbeans</artifactId>
        <version>2.6.0</version> 
        <exclusions>
            <exclusion>
                <groupId>stax</groupId>
                <artifactId>stax-api</artifactId>
            </exclusion>
            <exclusion>
                <groupId>xml-apis</groupId>
                <artifactId>xml-apis</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

【讨论】:

    【解决方案3】:

    javax.xml.bind.ContextFinder.find(Class[] classes, Map properties) 将首先寻找jaxb.property。 如果没有找到,它会尝试按以下顺序搜索/创建工厂:

    1. 系统属性javax.xml.bind.context.factory
    2. 使用 OSGi ServiceLoader 查找
    3. 搜索 META-INF 服务

    我相信您的程序不提供包com.my 中的jaxb.property。 所以工厂类是从 Websphere JDK/库加载的,它将返回一个 JAXBContext 类的对象。 但是该类与您的 WAR 中的类不同,所以 javax.xml.bind.ContextFinder 抛出 ClassCastException

    【讨论】:

    • 您的描述是正确的,但是我的 war 文件有一个用于 javax.xml.bind.* 类的 osgi 包装器。现在,问题是:如果我需要使用我自己的 javax.xml.bind.* 版本发送我的 war 文件,我有什么选择?
    猜你喜欢
    • 2023-04-04
    • 2017-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多