在Java/Maven中处理“Xerces hell”?历史问题解决 方案?

在我的办公室里,仅仅提到Xerces这个词就足以激起开发人员的杀戮愤怒。粗略地看一下SO上其他Xerces问题似乎表明,几乎所有Maven用户都在某个时候被这个问题“感动”。。不幸的是,理解这个问题需要对Xerces的历史有一点了解......

历史

  • Xerces是Java生态系统中使用最广泛的XML解析器。几乎每个用Java编写的库或框架都以某种方式使用Xerces(可传递的,如果不是直接的话)。

  • 官方二进制文件中包含的Xerces罐子直到今天还没有版本控制。例如,Xerces 2.11.0 实现 jar 被命名为 而不是 。xercesImpl.jarxercesImpl-2.11.0.jar

  • Xerces团队不使用Maven,这意味着他们不会将官方版本上传到Maven Central

  • Xerces曾经作为单个jar()发布,但被分成两个jar,一个包含API(),另一个包含这些API的实现()。许多较旧的 Maven POM 仍然声明依赖于 .在过去某个时候,Xerces也被发布为,一些较旧的POM也依赖于此。xerces.jarxml-apis.jarxercesImpl.jarxerces.jarxmlParserAPIs.jar

  • 那些将 jar 部署到 Maven 存储库的人分配给 xml-apis 和 xercesImpl jar 的版本通常是不同的。例如,xml-api 可能被赋予版本 1.3.03,xercesImpl 可能被赋予版本 2.8.0,即使两者都来自 Xerces 2.8.0。这是因为人们经常使用xml-apis jar实现的规范版本来标记它。这里有一个非常好但不完整的细分。

  • 更复杂的是,Xerces 是用于 JAVA API for XML Processing (JAXP) 的参考实现的 XML 解析器,包含在 JRE 中。实现类被重新打包在命名空间下,这使得直接访问它们变得危险,因为它们在某些 JRE 中可能不可用。但是,并非所有 Xerces 功能都通过 和 API 公开。例如,没有公开 Xerces 序列化的 API。com.sun.*java.*javax.*

  • 更糟糕的是,几乎所有的servlet容器(JBoss,Jetty,Glassfish,Tomcat等)都与Xerces一起放在一个或多个文件夹中。/lib

问题

冲突解决

出于上述一些原因,或者可能是所有原因,许多组织在其POM中发布和使用Xerces的自定义构建。如果你有一个小型应用程序并且只使用Maven Central,这并不是一个真正的问题,但对于Artifactory或Nexus代理多个存储库(JBoss,Hibernate等)的企业软件来说,这很快就会成为一个问题:

xml-apis proxied by Artifactory

例如,组织 A 可能发布为:xml-apis

<groupId>org.apache.xerces</groupId>
<artifactId>xml-apis</artifactId>
<version>2.9.1</version>

同时,组织 B 的发布可能与以下内容相同:jar

<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.3.04</version>

虽然B的版本比A的版本低,但Maven并不知道它们是同一个神器,因为它们有不同的s。因此,它无法执行冲突解决,并且两个都将作为已解决的依赖项包含在内:jarjargroupIdjar

resolved dependencies with multiple xml-apis

类装入器地狱

如上所述,JRE在JAXP RI中与Xerces一起提供。虽然将所有 Xerces Maven 依赖项标记为 s 或 为 会很好,但您依赖的第三方代码可能适用于您正在使用的 JDK 的 JAXP 中提供的版本,也可能不起作用。此外,您还可以将Xerces罐装在servlet容器中以进行处理。这给你留下了许多选择:你是否删除了 servlet 版本,并希望你的容器在 JAXP 版本上运行?离开 servlet 版本,并希望您的应用程序框架在 servlet 版本上运行是否更好?如果上面概述的一两个未解决的冲突设法滑入你的产品(在大型组织中很容易发生),你很快就会发现自己处于类加载器地狱中,想知道类加载器在运行时选择哪个版本的Xerces,以及它是否会在Windows和Linux中选择相同的jar(可能不是)。<exclusion><provided>

解决 方案?

我们尝试将所有 Xerces Maven 依赖项标记为 或 标记为 ,但这很难强制执行(特别是对于大型团队),因为工件具有如此多的别名(、、、、等)。此外,我们的第三方库/框架可能无法在 JAXP 版本或 Servlet 容器提供的版本上运行。<provided><exclusion>xml-apisxercesxercesImplxmlParserAPIs

我们如何最好地解决这个问题?我们是否必须对依赖关系进行这种细粒度的控制,然后依赖分层类加载?有没有办法全局排除所有 Xerces 依赖项,并强制我们所有的框架/库都使用 JAXP 版本?


更新:Joshua Spiewak已将Xerces构建脚本的补丁版本上传到XERCESJ-1454,允许上传到Maven Central。投票/观看/贡献这个问题,让我们一劳永逸地解决这个问题。


答案 1

自2013年2月20日以来,Maven Central有2.11.0 JAR(和源JAR!)的Xerces!参见Maven Central的Xerces。我想知道为什么他们没有解决 https://issues.apache.org/jira/browse/XERCESJ-1454...

我用过:

<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.11.0</version>
</dependency>

所有依赖关系都已解决 - 甚至正确!xml-apis-1.4.01

最重要的是(以及过去不明显的) - Maven Central中的JAR与官方Xerces-J-bin.2.11.0.zip发行版中的JAR相同

但是,我找不到版本 - 由于其他依赖项,它不能是Maven -ed版本。xml-schema-1.1-betaclassifier


答案 2

坦率地说,我们遇到的几乎所有东西都可以在JAXP版本中正常工作,因此我们总是排除和。xml-apisxercesImpl


推荐