Mavenでのクラスの重複チェック

ライブラリの管理にMavenやGradleを利用するのが一般的だと思いますが、個人的にいつも憎たらしく思うのがgroupIdやartifactIdがバージョンによって変わってくるケース。例えばこんなの。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

何が厄介かというと、groupIdとartifactIdが違うことによって別物と認識されるため、依存関係の連鎖の中で意図せず混入し、同一のFQCN(完全修飾クラス名)を持つクラスが複数存在することになります。

クラス重複の危険性

意図しないartifact、意図しないバージョンのクラスが読み込まれることで、実行時にメソッドがないよと例外が出たり、Slf4Jのアダプタと本家のクラスが混在したようなケースだと想定外の挙動をしたりします。

また、複数同一クラスが存在した場合は先に読み込まれた者勝ちとなり、また読み込み順もクラスパスの順、ファイルシステムでのjarファイルの並び順だったりとで規則性があり、どのクラスが読み込まれるかについては環境が一致していれば大体再現性があります。幸か不幸か、たまたま今までは意図したクラスが読み込まれて正常稼働していた場合でも何らかの環境の変化により、突然意図しないクラスが読み込まれて障害となることもあり、極力危ないものは除外しておきたいところです。

重複しているクラスを持つartifactを見つけるのは面倒

では、重複クラスをどう見つけるか、ですが、servlet-apiの様な例は分かりやすく簡単にチェックできるのですが、groupId/artifactIdが似ても似つかないものになっていたり、他アーティファクトのクラスを同梱してしまっていたりと、巧妙に隠されていることがあります。 1個1個JARを解凍して探すのも手でやるのは非常に面倒なので、簡単なスクリプトを作ってみました。

groovyがない場合でも動かせるよう実行可能JAR化できるようにgradleプロジェクトにしてあります。

github.com

ところで、作る前にも似たようなツールないか調べたのに、作ってから再度調べたらクラス重複チェックしてくれるmaven pluginが存在したようで…。

github.com