777

私のオフィスでは、Xerces という言葉に言及するだけで、開発者の殺意を掻き立てるのに十分です。SO に関する他の Xerces の質問をざっと見てみると、ほぼすべての Maven ユーザーがこの問題に「触れた」ことがあることがわかります。残念ながら、この問題を理解するには、Xerces の歴史について少し知識が必要です...

歴史

  • Xerces は、Java エコシステムで最も広く使用されている XML パーサーです。Java で記述されたほぼすべてのライブラリまたはフレームワークは、Xerces をある程度 (直接ではないにしても、推移的に) 使用します。

  • 公式バイナリに含まれる Xerces jar は、今日までバージョン管理されていません。たとえば、Xerces 2.11.0 実装 jar の名前はxercesImpl.jarではなく、xercesImpl-2.11.0.jar.

  • Xerces チームは Mavenを使用していません。つまり、公式リリースをMaven Centralにアップロードしていません。

  • Xerces は以前は単一の jar としてリリースされていました( ) が、API を含むもの ( ) とそれらの API の実装を含むもの( )xerces.jarの 2 つの jar に分割されました。古い Maven POM の多くは、依然として への依存関係を宣言しています。過去のある時点で、Xerces は としてもリリースされ、一部の古い POM も依存しています。xml-apis.jarxercesImpl.jarxerces.jarxmlParserAPIs.jar

  • jar を Maven リポジトリーにデプロイする人によって xml-apis および xercesImpl jar に割り当てられるバージョンは、多くの場合、異なります。たとえば、xml-apis にはバージョン 1.3.03 が指定され、xercesImpl にはバージョン 2.8.0 が指定される場合がありますが、どちらも Xerces 2.8.0 のものです。これは、xml-apis jar に、それが実装する仕様のバージョンのタグを付けることがよくあるためです。ここには、非常に素晴らしいが不完全な内訳があります

  • さらに複雑なことに、Xerces は、JRE に含まれる Java API for XML Processing (JAXP) のリファレンス実装で使用される XML パーサーです。実装クラスはcom.sun.*名前空間の下に再パッケージ化されているため、一部の JRE では使用できない可能性があるため、直接アクセスするのは危険です。ただし、すべての Xerces 機能がjava.*およびjavax.*API を介して公開されているわけではありません。たとえば、Xerces のシリアル化を公開する API はありません。

  • さらに混乱を招くのは、ほとんどすべてのサーブレット コンテナー (JBoss、Jetty、Glassfish、Tomcat など) が、1 つまたは複数の/libフォルダーに Xerces と共に出荷されていることです。

問題

紛争解決

上記の理由の一部、またはすべての理由から、多くの組織は 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>

Bjarは A よりも下位のバージョンですがjar、 Maven は が異なるため、それらが同じアーティファクトであることを知りません groupId。したがって、競合の解決を実行できず、両方 jarの が解決された依存関係として含まれます。

複数の xml-api で解決された依存関係

クラスローダー地獄

前述のように、JRE は JAXP RI の Xerces に同梱されています。すべての Xerces Maven 依存関係を<exclusion>s または asとしてマークすると便利ですが、<provided>依存しているサードパーティのコードは、使用している JDK の JAXP で提供されているバージョンで動作する場合と動作しない場合があります。さらに、競合するサーブレット コンテナに Xerces jar が同梱されています。これにより、多くの選択肢が残されます。サーブレット バージョンを削除し、コンテナーが JAXP バージョンで実行されることを望みますか? サーブレット バージョンを残し、アプリケーション フレームワークがサーブレット バージョンで実行されることを期待する方がよいでしょうか? 上記で概説した未解決の競合の 1 つまたは 2 つが製品に紛れ込んだ場合 (大規模な組織では発生しやすい)、すぐにクラスローダー地獄に陥り、クラスローダーが実行時に Xerces のどのバージョンを選択しているのか、またそれがWindowsとLinuxで同じjarを選択します(おそらくそうではありません)。

ソリューション?

<provided>すべての Xerces Maven 依存関係をまたは としてマークしようとしまし<exclusion>たが、成果物に非常に多くのエイリアス ( xml-apisxercesxercesImplxmlParserAPIsなど) があるため、これを強制するのは (特に大規模なチームでは) 困難です。さらに、サードパーティのライブラリ/フレームワークは、JAXP バージョンまたはサーブレット コンテナーによって提供されるバージョンでは実行できない場合があります。

Maven でこの問題に対処するにはどうすればよいでしょうか? 依存関係をそのようにきめ細かく制御してから、階層化されたクラスローディングに頼る必要がありますか? すべての Xerces 依存関係をグローバルに除外し、すべてのフレームワーク/ライブラリで JAXP バージョンを使用するように強制する方法はありますか?


更新: Joshua Spiewak は、Xerces ビルド スクリプトのパッチを適用したバージョンをXERCESJ-1454にアップロードしました。これにより、Maven Central へのアップロードが可能になります。この問題に投票/監視/貢献して、この問題を完全に修正しましょう。

4

11 に答える 11

119

2013 年 2 月 20 日以降、Maven Central には Xerces の2.11.0 JAR (およびソース JAR)があります。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 は、公式ディストリビューションの JAR と同じXerces-J-bin.2.11.0.zipです。

ただし、バージョンを見つけることができませんでした。依存関係が追加されているためxml-schema-1.1-beta、Mavenバージョンにすることはできません。classifier

于 2013-03-07T07:30:21.040 に答える
66

率直に言って、これまでに遭遇したほとんどすべてが JAXP バージョンで問題なく動作するため、常にとを除外 xml-apisxercesImplます。

于 2012-07-26T22:18:36.327 に答える
44

禁止された依存関係ルールで maven エンフォーサ プラグインを使用できます。これにより、不要なエイリアスをすべて禁止し、必要なものだけを許可することができます。これらのルールに違反すると、プロジェクトの Maven ビルドが失敗します。さらに、このルールがエンタープライズ内のすべてのプロジェクトに適用される場合、プラグイン構成を企業の親 pom に配置できます。

見る:

于 2012-07-27T16:28:38.507 に答える
37

私はこれが質問に正確に答えていないことを知っていますが、たまたま依存関係管理にGradleを使用しているGoogleから来るpplの場合:

次のように、Gradle で xerces/Java8 の問題をすべて取り除くことができました。

configurations {
    all*.exclude group: 'xml-apis'
    all*.exclude group: 'xerces'
}
于 2015-04-24T06:54:38.963 に答える
16

答えなければならない質問が 1 つあります。

アプリケーション内のすべてのものと一緒に使用できる xerces*.jar はありますか?

そうでない場合は、基本的にめちゃくちゃで、OSGI のようなものを使用する必要があります。これにより、異なるバージョンのライブラリを同時にロードできます。基本的にjarバージョンの問題をクラスローダーの問題に置き換えることに注意してください...

そのようなバージョンが存在する場合は、リポジトリがあらゆる種類の依存関係に対してそのバージョンを返すようにすることができます。これは醜いハックであり、クラスパスに同じ xerces 実装が複数回発生することになりますが、複数の異なるバージョンの xerces を使用するよりはましです。

xerces へのすべての依存関係を除外し、使用するバージョンに 1 つ追加することができます。

Mavenのプラグインとして、ある種のバージョン解決戦略を書くことができるのだろうか. これはおそらく最も優れた解決策ですが、実行可能な場合は、調査とコーディングが必要です。

ランタイム環境に含まれるバージョンについては、アプリケーションのクラスパスから削除するか、サーバーの lib フォルダーが考慮される前にアプリケーションの jar ファイルがクラスロードの対象になることを確認する必要があります。

まとめとして、これは混乱しており、それは変わりません。

于 2012-07-26T20:49:39.367 に答える
9

XML地獄のレベルを特定するために、最初にデバッグする必要があります。私の意見では、最初のステップは追加することです

-Djavax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
-Djavax.xml.transform.TransformerFactory=com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl
-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl

コマンドラインに。それが機能する場合は、ライブラリの除外を開始します。そうでない場合は、追加します

-Djaxp.debug=1

コマンドラインに。

于 2016-06-14T13:51:53.637 に答える
8

ここでは検討されていない別のオプションがあります: Maven で Xerces の依存関係をオプションとして宣言する:

<dependency>
   <groupId>xerces</groupId>
   <artifactId>xercesImpl</artifactId>
   <version>...</version>
   <optional>true</optional>
</dependency>

基本的にこれが行うことは、すべての依存関係にXerces のバージョンを宣言するように強制することです。そうしないと、プロジェクトがコンパイルされませんこの依存関係をオーバーライドしたい場合は、それを歓迎しますが、潜在的な問題を抱えていることになります。

これにより、下流のプロジェクトが次のことを行う強力なインセンティブが作成されます。

  • 積極的に決断してください。彼らは同じバージョンの Xerces を使用していますか、それとも別のものを使用していますか?
  • クラスパスを乱雑にしないだけでなく、実際に解析 (単体テストなど) とクラスローディングをテストします。

すべての開発者が、新たに導入された依存関係を追跡しているわけではありません (例: などmvn dependency:tree)。このアプローチにより、すぐに問題に注意を向けることができます。

私たちの組織では非常にうまく機能しています。その導入の前に、私たちはOPが説明しているのと同じ地獄に住んでいました.

于 2015-10-02T09:52:51.990 に答える
6

すべての Maven プロジェクトは、xerces に依存するのをやめるべきです。おそらく、そうではありません。XML API と Impl は、Java 1.4 以降の一部です。xerces や XML API に依存する必要はありません。Java や Swing に依存していると言うようなものです。これは暗黙的です。

もし私が Maven リポジトリのボスだったら、xerces の依存関係を再帰的に削除するスクリプトを書き、このリポジトリには Java 1.4 が必要であると書いて読んでもらいます。

org.apache インポートを介して Xerces を直接参照するために実際に機能しないものはすべて、Java 1.4 レベル (および 2002 年以降) に引き上げるためのコード修正、または Maven ではなく、承認されたライブラリを介した JVM レベルでの解決策が必要です。

于 2016-02-05T11:58:43.507 に答える
2

どうやらxerces:xml-apis:1.4.01、maven の中心ではなくなったようですが、これは何をxerces:xercesImpl:2.11.0参照していますか。

これは私のために働く:

<dependency>
  <groupId>xerces</groupId>
  <artifactId>xercesImpl</artifactId>
  <version>2.11.0</version>
  <exclusions>
    <exclusion>
      <groupId>xerces</groupId>
      <artifactId>xml-apis</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>xml-apis</groupId>
  <artifactId>xml-apis</artifactId>
  <version>1.4.01</version>
</dependency>
于 2016-10-04T16:45:02.570 に答える
2

除外する以外に役立つのは、モジュールの依存関係です。

1 つのフラット クラスローディング (スタンドアロン アプリ) または半階層 (JBoss AS/EAP 5.x) では、これが問題でした。

しかし、OSGiJBoss Modulesなどのモジュラー フレームワークを使用すると、これはそれほど苦痛ではなくなります。ライブラリは、必要なライブラリを個別に使用できます。

もちろん、単一の実装とバージョンに固執することが依然として最も推奨されますが、他に方法がない場合 (より多くのライブラリの追加機能を使用する) は、モジュール化することで解決できる可能性があります。

実際の JBoss モジュールの良い例は、当然ながらJBoss AS 7 / EAP 6 / WildFly 8であり、主に開発されたものです。

モジュール定義の例:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.jboss.msc">
    <main-class name="org.jboss.msc.Version"/>
    <properties>
        <property name="my.property" value="foo"/>
    </properties>
    <resources>
        <resource-root path="jboss-msc-1.0.1.GA.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="org.jboss.logging"/>
        <module name="org.jboss.modules"/>
        <!-- Optional deps -->
        <module name="javax.inject.api" optional="true"/>
        <module name="org.jboss.threads" optional="true"/>
    </dependencies>
</module>

OSGi と比較して、JBoss Modules はよりシンプルで高速です。特定の機能が欠けていますが、(ほとんど) 1 つのベンダーの管理下にあり、(並列化された依存関係の解決により) 驚異的な高速起動を可能にするほとんどのプロジェクトには十分です。

Java 8のモジュール化の取り組みが進行中であることに注意してください。ただし、これは主に JRE 自体をモジュール化することであり、アプリに適用できるかどうかはわかりません。

于 2013-06-22T02:59:50.853 に答える