9

我已经更新了我们的项目(基于在 Websphere 8.5 上运行的 Java EE)以使用公司内部框架的新版本(以及 Ejb 3.x 部署描述符而不是 2.x 部署描述符)。从那时起,我的集成测试失败,但出现以下异常:

 [java.lang.ClassNotFoundException: com.ibm.xml.xlxp2.jaxb.JAXBContextFactory]

我可以使用以前的框架版本构建应用程序,并且一切正常。在调试时,我注意到在 ContextFinder (javax.xml.bind) 中有两种不同的行为:

  1. 以前的版本(一切正常):不同的地方没有一个工厂类,所以默认的工厂类被加载,它是 com.sun.xml.internal.bind.v2.ContextFactory (定义为类中的字符串常量) .

  2. 升级版本(ClassNotFound):成功加载资源“META-INF/services/javax.xml.bind.JAXBContext”,第一行读取使 ContextFinder 尝试加载“com.ibm.xml.xlxp2.jaxb。 JAXBContextFactory”导致错误。

我现在有两个问题:

  1. 那个资源是什么类型的?因为在我们的 EAR 中有两个 WAR,而这两个中没有一个在其 META-INF 目录中包含文件夹 services。

  2. 否则,该价值从何而来?因为 filediff 向我显示没有新的或更改的属性文件。

不用说我将阅读有关 JAXB 配置可能性的所有信息,但如果您对可能出现的问题有初步见解或帮助我解决该资源(这是我必须寻找的真实文件吗?)我很感激很多。非常感谢!

编辑(根据评论输入/问题):

出于好奇,您的框架是否包含 JAXB JAR?您的框架的旧版本是否包含 jaxb.properties?

确实(我有点惊讶)该框架在 EAR 中有一个自定义的 eclipselink-2.4.1-.jar,其中包括一个 JAXB 实现和一个 jaxb.properties 文件,该文件在两个版本中显示以下条目(找到工厂以及引发异常的工厂):

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

我认为这与当前问题无关,因为 jar 在两个 EAR 中保持完全相同(运行的那个 / 有期望的那个)

我也不清楚为什么旧版本的框架会选择 com.sun 实现

有一个类 javax.xml.bind.ContextFinder 负责初始化 JAXBContextFactory。此类搜索各个地方是否存在 jaxb.properties 文件或“javax.xml.bind.JAXBContext”资源。如果所有这些地方都没有显示要使用哪个上下文工厂,则加载了一个默认工厂,该工厂在类本身中被硬编码:

private static final String PLATFORM_DEFAULT_FACTORY_CLASS = "com.sun.xml.internal.bind.v2.ContextFactory";

现在回到我的问题:

使用先前版本的框架(和 EJB 2.x 部署描述符)构建一切正常)。在调试时我可以看到没有找到配置,因此上面提到的默认工厂已加载。

使用新版本的框架(和 EJB 3.x 部署描述符,以便我可以部署)构建只有一个 TESTCASE 失败,但其余功能有效(就像我可以向我们的 web 服务发送请求并且它们不会触发任何错误)。在调试时,我可以看到找到了一个配置。此资源名为“META-INF/services/javax.xml.bind.JAXBContext”。以下是该资源如何导致尝试加载“com.ibm.xml.xlxp2.jaxb.JAXBContextFactory”的最重要的几行,然后抛出 ClassNotFoundException。这是所提到的 javax.xml.bind.ContextFinder 类的简化源代码:

URL resourceURL = ClassLoader.getSystemResource("META-INF/services/javax.xml.bind.JAXBContext");

BufferedReader r = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "UTF-8"));

String factoryClassName = r.readLine().trim();  

字段 factoryClassName 现在具有值“com.ibm.xml.xlxp2.jaxb.JAXBContextFactory”

因为这已经成为一个超级大的问题,所以我还将增加一个赏金:) 我会为此工作一整天,如果有任何消息,请告诉你。

更新/解决方案

这个问题已经解决了。最初的问题发生是因为复杂构建多模型 maven 项目的错误配置,其中一个依赖项使用了自定义 eclipse 链接 jar 的更新版本,其中包含 JAXBFactory 的定义,该定义在发生错误的组件中不可用。在大多数情况下,设置 JAXB 上下文工厂是使用包含相同定义的 jaxb.propertie 文件或 JAXBContext 文件进行配置的。相应 JAXBContextFactory 的详细加载过程发生在 javax.xml.bind.ContextFinder 中。

该错误尚未解决(实际上超过 4 个主要的 EE/SE 应用程序导致错误)并且没有一般的答案,但定义的 JAXBContextFactorys 必须存在于您的类路径中(哇,真是个奇迹......)所以你要么有一个 ClassNotFound 错误,因为您缺少资源(这就是实际原因),或者因为您在上述任何包含根据以下答案的定义的属性文件中定义了错误的 JAXBContextFactory。

非常感谢您的好评和支持,我真的很感激!

4

2 回答 2

6

您可以jaxb.properties在与域模型相同的包中包含一个文件,以指定您希望使用的 JAXB ( JSR-222 ) 实现。例如,将EclipseLink MOXy指定为您的 JAXB 提供程序将如下所示。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

了解更多信息

于 2013-11-01T17:14:12.293 回答
4

另一个对我有用的快速而肮脏的解决方案(实际上是一种解决方法)是将 JAXB 实现显式包含到 maven 构建中。例如

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.2.7</version>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>2.2.7</version>
</dependency>

请注意,这会为您的构建添加某种不必要的依赖关系,因为 JAXB 显然已经是每个 JRE >= 版本 6 的一部分。

这很可能仅在 WAS 类加载器最后设置为父级时才有效。

于 2014-01-14T14:02:27.007 回答