Gradleは元々の作りが非常にブラックボックスなため、設定されたオブジェクトのライフサイクルがわかりづらいなどの問題があり、Gradle3に向けて、それを修正している最中です。その中核となるのがRule Based Model Configurationという仕組みです。
その仕組については以前にもエントリーを書いているので、そちらを参照してください。
基本的な考え方は
- 値オブジェクトの生成(プラグインが値オブジェクトを生成する)
- 値オブジェクトの設定(ユーザーがオブジェクトの中の値を変更できる/mutableなオブジェクト)
- 値の利用(ユーザーもプラグインも値を変更できない/immutableなオブジェクト)
という流れにそって設定を記述していくという考え方です。
では、Javaプロジェクトはどのように変わっていくかを今回は簡単に説明するとともに、簡単なプロジェクトを作ってみます。
プラグイン
これまではJavaプロジェクトの場合は次のように記述していました。
apply plugin: 'java'
あるいはGradle2.2以降であれば、次のようにも記述できました。
plugins {
id 'java'
}
Gradle3以降のJavaプロジェクトではこの部分が次のように変わります。
plugins { id 'jvm-component' id 'java-lang' }
jvm-component
プラグインとjava-lang
プラグインの二つを利用します。
jvm-component
プラグインでは主にJVM系のプラグインに共通のディレクトリーセットなどをrule based modelオブジェクトに従って定義します。java-lang
プラグインではJavaに特化したディレクトリーセットや成果物生成のタスクなどをrule based modelオブジェクトに従って定義します。
コンポーネント
上記の最後のほうで、「rule based modelオブジェクトに従って定義します」という言葉を何度も使いました。これはビルドスクリプトの中でmodel{}
ブロック内で定義されるコンポーネント(components
)というオブジェクトがプロジェクトのディレクトリー構造などを決定することを意味します。
そこで、我々もmodel{}
ブロック内においてcomponents
オブジェクトに値を設定してみたいと思います。
model { components { main(JvmLibrarySpec) } }
さて、この記述をした後で、components
タスクを実行してみてください。
$ gradle components :components ------------------------------------------------------------ Root project ------------------------------------------------------------ JVM library 'main' ------------------ Source sets Java source 'main:java' srcDir: src/main/java JVM resources 'main:resources' srcDir: src/main/resources Binaries Jar 'mainJar' build using task: :mainJar targetPlatform: Java SE 8 tool chain: JDK 8 (1.8) Jar file: build/jars/mainJar/main.jar Note: currently not all plugins register their components, so some components may not be visible here. BUILD SUCCESSFUL Total time: 0.793 secs $
この段階で、以下の情報がわかります。
- ライブラリーの名前は
main
- ソースは
src/main/java
ディレクトリー以下に配置される - リソースファイルは
src/main/resources
ディレクトリー以下に配置される - 生成されるクラスファイルのターゲットプラットフォームはJava8
- 作成されるjarのディレクトリーと名前は
build/jars/mainJar/main.jar
コンポーネントはいくつでも作ることができます。例えば、次のように記述することでmain
というライブラリーとsub
というライブラリーが作成されます。
model { components { main(JvmLibrarySpec) sub(JvmLibrarySpec) } }
この場合、それぞれのディレクトリーは次のようになります。
ライブラリー | ソース | リソース | Jarファイル |
---|---|---|---|
main |
src/main/java |
src/main/resources |
build/jars/mainJar/main.jar |
sub |
src/sub/java |
src/sub/resources |
build/jars/subJar/sub.jar |
ビルド
さて、問題を簡単にするためにsub
ライブラリーには消えてもらうことにします。
src/main/java
およびsrc/main/resources
にファイルを作ってみましょう。
src/main/java/sample/Main.java
package sample; import java.io.IOException; public class Main { public static void main(String... args) throws IOException { Res res = new Res(); System.out.println(res.getMessage("message")); System.out.println(res.getMessage("name")); System.out.println(res.getMessage("my")); } }
src/main/java/sample/Res.java
package sample; import java.io.InputStream; import java.io.InputStreamReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Properties; public class Res { private final Properties prop; public Res() throws IOException { ClassLoader cl = getClass().getClassLoader(); prop = new Properties(); try(InputStream is = cl.getResourceAsStream("app.properties")) { InputStreamReader r = new InputStreamReader(is, StandardCharsets.UTF_8); prop.load(r); } } public String getMessage(String key) { return prop.getProperty(key, "<no-entry>"); } }
src/main/resources/app.properties
message=こんにちわ name=mikeさん my=僕はGradle
では、これをビルドします。ビルドコマンドはgradle build
です。
$ gradle clean build :clean :compileMainJarMainJava :processMainJarMainResources :createMainJar :mainJar :assemble :check UP-TO-DATE :build BUILD SUCCESSFUL Total time: 0.847 secs $
というわけで、出来上がったようです。
成果物の位置も調べてみます。
$ tree build build ├── classes │ └── mainJar │ ├── META-INF │ ├── app.properties │ └── sample │ ├── Main.class │ └── Res.class ├── jars │ └── mainJar │ └── main.jar ├── jvm-dep-cache └── tmp ├── compileMainJarMainJava └── createMainJar └── MANIFEST.MF 10 directories, 5 files
build/jars/mainJar/main.jar
に成果物が作成されています。
では、実行してみますが、ちょっと調べたのですが、MANIFEST.MF
をいじるためのDSLが見当たりませんでした(´・ω・`)
そのため、-cp
でjarを読み込んでメインクラスを指定して実行します。
$ java -cp build/jars/mainJar/main.jar sample.Main こんにちわ mikeさん 僕はGradle
はい、まあ、大したことのないプロジェクトですね。
以上がJVM component modelを用いたJavaプロジェクトの作成入門でした。
なお、今回作成したプロジェクトのサンプルは以下のレポジトリーから取得できます。
次回(あるかどうかは知らない)はJVM component modelとJava9 Project Jigsawの関係について言及できればいいなぁ…