在Java / Maven中处理“Xerces hell”?

喜夏-厌秋 提交于 2020-08-14 11:29:49

问题:

In my office, the mere mention of the word Xerces is enough to incite murderous rage from developers. 在我的办公室里,仅仅提到Xerces这个词就足以煽动开发者的凶悍愤怒。 A cursory glance at the other Xerces questions on SO seem to indicate that almost all Maven users are "touched" by this problem at some point. 粗略地看一眼其他Xerces关于SO的问题似乎表明,几乎所有Maven用户都会在某个时候“触及”这个问题。 Unfortunately, understanding the problem requires a bit of knowledge about the history of Xerces... 不幸的是,理解这个问题需要对Xerces的历史有一点了解......

History 历史

  • Xerces is the most widely used XML parser in the Java ecosystem. Xerces是Java生态系统中使用最广泛的XML解析器。 Almost every library or framework written in Java uses Xerces in some capacity (transitively, if not directly). 几乎每个用Java编写的库或框架都以某种身份使用Xerces(传递,如果不是直接的话)。

  • The Xerces jars included in the official binaries are, to this day, not versioned. 包含在官方二进制文件中的Xerces罐子直到今天还没有版本化。 For example, the Xerces 2.11.0 implementation jar is named xercesImpl.jar and not xercesImpl-2.11.0.jar . 例如,Xerces 2.11.0实现jar被命名为xercesImpl.jar而不是xercesImpl-2.11.0.jar

  • The Xerces team does not use Maven , which means they do not upload an official release to Maven Central . Xerces团队不使用Maven ,这意味着他们不会将正式版本上传到Maven Central

  • Xerces used to be released as a single jar ( xerces.jar ), but was split into two jars, one containing the API ( xml-apis.jar ) and one containing the implementations of those APIs ( xercesImpl.jar ). Xerces曾经作为单个jarxerces.jar )发布,但被分成两个jar,一个包含API( xml-apis.jar ),另一个包含这些API的实现( xercesImpl.jar )。 Many older Maven POMs still declare a dependency on xerces.jar . 许多较旧的Maven POM仍声明对xerces.jar的依赖。 At some point in the past, Xerces was also released as xmlParserAPIs.jar , which some older POMs also depend on. 在过去的某个时刻,Xerces也被发布为xmlParserAPIs.jar ,一些较旧的POM也依赖于它。

  • The versions assigned to the xml-apis and xercesImpl jars by those who deploy their jars to Maven repositories are often different. 分配给xml-apis和xercesImpl的版本由那些将其jar部署到Maven存储库的人通常是不同的。 For example, xml-apis might be given version 1.3.03 and xercesImpl might be given version 2.8.0, even though both are from Xerces 2.8.0. 例如,xml-apis可能是1.3.03版本,而xercesImpl可能是2.8.0版本,即使两者都来自Xerces 2.8.0。 This is because people often tag the xml-apis jar with the version of the specifications that it implements. 这是因为人们经常使用它实现的规范版本来标记xml-apis jar。 There is a very nice, but incomplete breakdown of this here . 还有就是这是一个非常不错的,但不完全击穿这里

  • To complicate matters, Xerces is the XML parser used in the reference implementation of the Java API for XML Processing (JAXP), included in the JRE. 更复杂的是,Xerces是包含在JRE中的Java API for XML Processing(JAXP)的参考实现中使用的XML解析器。 The implementation classes are repackaged under the com.sun.* namespace, which makes it dangerous to access them directly, as they may not be available in some JREs. 实现类在com.sun.*命名空间下重新打包,这使得直接访问它们很危险,因为它们可能在某些JRE中不可用。 However, not all of the Xerces functionality is exposed via the java.* and javax.* APIs; 但是,并非所有Xerces功能都通过java.*javax.* API公开; for example, there is no API that exposes Xerces serialization. 例如,没有API公开Xerces序列化。

  • Adding to the confusing mess, almost all servlet containers (JBoss, Jetty, Glassfish, Tomcat, etc.), ship with Xerces in one or more of their /lib folders. 添加到令人困惑的混乱中,几乎所有servlet容器(JBoss,Jetty,Glassfish,Tomcat等)都在一个或多个/lib文件夹中附带Xerces。

Problems 问题

Conflict Resolution 解决冲突

For some -- or perhaps all -- of the reasons above, many organizations publish and consume custom builds of Xerces in their POMs. 对于上述某些原因(或许是全部原因),许多组织在其POM中发布和使用Xerces的自定义构建。 This is not really a problem if you have a small application and are only using Maven Central, but it quickly becomes an issue for enterprise software where Artifactory or Nexus is proxying multiple repositories (JBoss, Hibernate, etc.): 如果你有一个小应用程序并且只使用Maven Central,这不是一个真正的问题,但它很快成为企业软件的问题,其中Artifactory或Nexus代理多个存储库(JBoss,Hibernate等):

由Artifactory代理的xml-apis

For example, organization A might publish xml-apis as: 例如,组织A可能会将xml-apis发布为:

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

Meanwhile, organization B might publish the same jar as: 同时,组织B可能会发布相同的jar

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

Although B's jar is a lower version than A's jar , Maven does not know that they are the same artifact because they have different groupId s. 虽然B的jar是比A的jar更低的版本,但Maven并不知道它们是相同的工件,因为它们有不同的groupId Thus, it cannot perform conflict resolution and both jar s will be included as resolved dependencies: 因此,它无法执行冲突解决,并且两个jar都将作为已解析的依赖项包含在内:

使用多个xml-apis解决了依赖关系

Classloader Hell Classloader Hell

As mentioned above, the JRE ships with Xerces in the JAXP RI. 如上所述,JRE在JAXP RI中附带Xerces。 While it would be nice to mark all Xerces Maven dependencies as <exclusion> s or as <provided> , the third-party code you depend on may or may not work with the version provided in JAXP of the JDK you're using. 虽然将所有Xerces Maven依赖项标记为<exclusion><provided>会很好,但您所依赖的第三方代码可能会也可能不会与您正在使用的JDK的JAXP中提供的版本一起使用。 In addition, you have the Xerces jars shipped in your servlet container to contend with. 此外,您还可以在servlet容器中附带Xerces jar以进行竞争。 This leaves you with a number of choices: Do you delete the servlet version and hope that your container runs on the JAXP version? 这给您留下了许多选择:您是否删除了servlet版本并希望您的容器在JAXP版本上运行? Is it better to leave the servlet version, and hope that your application frameworks run on the servlet version? 离开servlet版本是否更好,并希望您的应用程序框架在servlet版本上运行? If one or two of the unresolved conflicts outlined above manage to slip into your product (easy to happen in a large organization), you quickly find yourself in classloader hell, wondering which version of Xerces the classloader is picking at runtime and whether or not it will pick the same jar in Windows and Linux (probably not). 如果上面列出的一个或两个未解决的冲突进入您的产品(很容易在大型组织中发生),您很快就会发现自己处于类加载器地狱,想知道类加载器在运行时选择的Xerces版本以及是否将在Windows和Linux中选择相同的jar(可能不是)。

Solutions? 解决方案?

We've tried marking all Xerces Maven dependencies as <provided> or as an <exclusion> , but this is difficult to enforce (especially with a large team) given that the artifacts have so many aliases ( xml-apis , xerces , xercesImpl , xmlParserAPIs , etc.). 我们已经尝试将所有Xerces Maven依赖项标记为<provided><exclusion> ,但这很难强制执行(特别是对于大型团队),因为工件有很多别名( xml-apisxercesxercesImplxmlParserAPIs等)。 Additionally, our third party libs/frameworks may not run on the JAXP version or the version provided by a servlet container. 此外,我们的第三方库/框架可能无法在JAXP版本或servlet容器提供的版本上运行。

How can we best address this problem with Maven? 我们怎样才能最好地解决Maven的这个问题? Do we have to exercise such fine-grained control over our dependencies, and then rely on tiered classloading? 我们是否必须对依赖关系进行如此细粒度的控制,然后依赖分层类加载? Is there some way to globally exclude all Xerces dependencies, and force all of our frameworks/libs to use the JAXP version? 有没有办法全局排除所有Xerces依赖项,并强制我们所有的框架/库使用JAXP版本?


UPDATE : Joshua Spiewak has uploaded a patched version of the Xerces build scripts to XERCESJ-1454 that allows for upload to Maven Central. 更新 :Joshua Spiewak已将Xerces构建脚本的修补版本上传到XERCESJ-1454 ,允许上传到Maven Central。 Vote/watch/contribute to this issue and let's fix this problem once and for all. 投票/观看/贡献这个问题,让我们一劳永逸地解决这个问题。


解决方案:

参考一: https://stackoom.com/question/mzrw/在Java-Maven中处理-Xerces-hell
参考二: https://oldbug.net/q/mzrw/Dealing-with-Xerces-hell-in-Java-Maven
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!