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

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

历史

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

  • 包含在官方二进制文件中的Xerces罐子至今仍未进行版本控制。 例如,Xerces 2.11.0实现jar被命名为xercesImpl.jar而不是xercesImpl-2.11.0.jar

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

  • 的Xerces用来释放为单罐( xerces.jar ),但被分成两个罐,一个包含API( xml-apis.jar )和含有这些API(的实现中,一个xercesImpl.jar )。 许多较老的Maven POM仍然声明对xerces.jar的依赖。 在过去的某个时候,Xerces也以xmlParserAPIs.jar发布,一些较老的POM也依赖它。

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

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

  • 除此之外,几乎所有的servlet容器(JBoss,Jetty,Glassfish,Tomcat等)都在Xerces的一个或多个/lib文件夹中提供。

  • 问题

    解决冲突

    对于上面的一些原因或者全部原因,许多组织在他们的POM中发布和使用Xerces的自定义版本。 如果你有一个小应用程序并且只使用Maven Central,这并不是一个问题,但是它很快就会成为Artifactory或Nexus代理多个存储库(JBoss,Hibernate等)的企业软件的一个问题:

    由Artifactory代理的xml-apis

    例如,组织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的jar比A的jar版本低,但Maven并不知道它们是相同的工件,因为它们有不同的groupId 。 因此,它不能执行冲突解决,并且这两个jar都将被包含为已解决的依赖关系:

    类加载器地狱

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

    解决方案?

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

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


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


    自2013年2月20日起,Maven Central中有2.11.0个xerces的JAR (和源JARs!) ! 参见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相同

    我无法找到xml-schema-1.1-beta版本 - 因为附加的依赖关系,它不能成为Maven classifier版本。


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


    你可以使用maven执行者插件和禁止的依赖规则。 这将允许你禁止你不想要的所有别名,只允许你想要的别名。 这些规则违反了你的项目的Maven构建。 此外,如果此规则适用于企业中的所有项目,则可以将插件配置放入公司父项目中。

    看到:

  • http://maven.apache.org/plugins/maven-enforcer-plugin/
  • http://maven.apache.org/enforcer/enforcer-rules/bannedDependencies.html
  • 链接地址: http://www.djcxy.com/p/7669.html

    上一篇: Dealing with "Xerces hell" in Java/Maven?

    下一篇: What's the point of Spring MVC's DelegatingFilterProxy?