なにか作る

なにかを作るブログです。

Gradle で BOM を使いたいときには Spring チームの出している Dependency management plugin を使うのがよさそう

Maven にある BOM の仕組みが Gradle には無い

Java の世界、時代は Maven から Gradle に移行しつつある。しかし、だからと言って安易な気持ちで Gradle を選択すると痛い目に合うこともある。Gradle が Maven の上位互換ではないからだ。例えば、Maven にある BOM の仕組みが Gradle には無い。

Maven の BOM (bill of materials) という仕組みは、プロダクトの一連の依存性のバージョンを定義した一覧表であり、利用者はその BOM のバージョンを指定さえすれば、個々の依存性のバージョンを指定する必要がなくなるというもの。たとえば Java EE のテスティングフレームワークである Arquillian では arquillian-bom という BOM を提供しており、以下のように arquillian-bom を読み込むことで、関連する Arquillian のライブラリのバージョンを記述する必要がなくなる。

pom.xml

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.arquillian</groupId>
            <artifactId>arquillian-bom</artifactId>
            <version>1.1.8.Final</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.jboss.arquillian.junit</groupId>
        <artifactId>arquillian-junit-container</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.jboss.shrinkwrap.resolver</groupId>
        <artifactId>shrinkwrap-resolver-depchain</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

残念ながらこの仕組みがない Gradle では arquillian-bom の pom.xml に記述された依存ライブラリのバージョンを一つ一つ指定してあげる必要があるわけだ。

build.gradle

dependencies {
  testCompile 'org.jboss.arquillian.junit:arquillian-junit-container:1.1.8.Final'
  testCompile 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-depchain:2.1.1'
}

これが 2 つしかないなら大した問題ではないのだが、BOM を提供しているようなフレームワークでは大抵 2 つや 3 つでは済まないのだ…。

Dependency management plugin を使えば Gradle で BOM の仕組みを再現できる

これを解決するのが Spring チームが出してる Dependency management plugin だ。このプラグインを導入することで、Maven で使用している BOM の機能を polyfill 的に Gradle でも使用できるようになる。

導入は簡単。まずはプラグインを適用し、

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE"
    }
}

apply plugin: "io.spring.dependency-management"

BOM をインポートする。

dependencyManagement {
  imports {
    mavenBom 'org.jboss.arquillian:arquillian-bom:1.1.8.Final'
  }
}

あとは、これまで同様、個々のライブラリを指定してあげる。ただし、バージョンの指定は不要。

dependencies {
  testCompile 'org.jboss.arquillian.junit:arquillian-junit-container'
  testCompile 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-depchain'
}

以上。なかなか便利だ。特に Spring のように様々なライブラリが複雑に絡み合っているフレームワークを使用する際には重宝するだろう。

一点注意なのが、このプラグインを導入することで、もうひとつ機能が追加されること。それが、Maven の exclusion が適用されるようになるというもの。これはこれで便利な機能だが、プラグインを導入するだけでデフォルトで有効になるので、プラグイン導入前後で読み込まれる依存性が変化する可能性が出てくる。無効にする場合は以下のようにする。

dependencyManagement {
  applyMavenExclusions false
}

Dependency management plugin は Spring Boot 1.3 でも採用される予定

Spring Blog のこのプラグインの紹介記事では、Spring Boot でもこのプラグインを採用する(元の spring-boot プラグインと併用して使うことになる)ことをアナウンスしている。

In the forthcoming Spring Boot 1.3 we have removed Boot’s own dependency management and started using the dependency management plugin instead.

なので、このプラグインがすぐになくなってしまうようなことも無さそうだ。