Gradle で optional のようなものを実現するには

バージョン情報

  • Gradle 6.0.1
  • propdeps plugin 0.0.9
  • maven 3.6.2

一言で言うと

featureVariants を使う。

詳しく言うと

Spring Boot などで auto configuration を実装しようとする場合など、対象のサポートをするが必須ではないライブラリを使うようにしたい場合がある*1

maven の場合はoptionalタグを true にすることで、開発しているライブラリ側では利用することができるがそのライブラリを利用する側では無視される*2

gradle の場合は方法としては 2 つ

それぞれ違いがあるが適当にかくと以下のような感じ。

方法 pom.xml 出力 plugin artifact 出力タスク 備考
propdeps plugin を使う maven uploadArchives gradle 6.0 以降では maven plugin を用いた publish は非推奨
featureVariants を使う maven-publish publish maven plugin では optional を出力できない

(最近はまだ gradle module metadata はあまり使われている気配はないので割愛)

propdeps plugin について

propdeps pluguin は spring team が作っている gradle plugin。 optional configuration を追加し、 maven での optional のような動きをするようにする。

挙動としては compile configuration の classpathoptional configuration を追加する。挙動としては compileOnly とほぼ同じ気はする。 ライブラリとして publish する場合には propdeps-maven plugin を利用し、 <scope>optional</scope> という(maven の仕様にはない) scope を一旦追加したあと gradle core apiuploadArchives task を用いる場合に <scope>compile</scope><optional>true</optional> に差し替えて pom.xml を出力する。ちなみに maven plugin にしか対応してないので maven-publish plugin で publish task を実行した場合 は <scope>optional</scope> で pom.xml が出力されてしまい思ったように動かなくなるかもしれない。

使うべきかどうかについては、おそらく新規では採用しない方がよさそう。というのも propdeps plugin はしばらく更新もされておらず(2017 年最終)、publish に使用する maven plugin が gradle 6.0 以上で deprecated, gradle 7.0 以上で 削除予定なのであまり利用しない方がよさそう*3。中で使ってるgradle のバージョンも 3.3 でだいぶ古い*4

featureVariants について

Gradle 5.3 から導入されている機能*5。詳しい説明は Modeling feature variants and optional dependencies を参照。

ドキュメントにも以下のように記載がある。

a (better) substitute for Maven optional dependencies

自分の理解としては 1つの componentvariantsimplementationruntime 等)を跨いで何らかの利用するかどうかを選択できる機能を実現する場合などに利用する*6

local component*7 や gradle module metadata としてそのライブラリを依存に含めて利用する場合は capability として名前をつけていくつかの依存をまとめて 依存に含めることができたりする。そうでない maven や ivy(コチラはよく知らない)などの external component はそれらに対応する機能に変換されて出力され、 maven-publish plugin の場合は その依存モジュールに <optional>true</optional> が付与される*8

ちなみに Modeling feature variants and optional dependencies には 以下のように記載があるが pom.xml には classifier タグとして出力される気配がないのでよくわからない。

using POM metadata (Maven), feature variants are published as optional dependencies and artifacts of feature variants are published with different classifiers

gradle 単体で運用してるならば capability の指定(capability の命名規則はデフォルトでは group:artifactId-(feature name の kebab case))により意味のある名前でまとめて 依存追加できるし maven repo への publish もサポートしてるので こちらの方がよさそうに見える。