Gradleプロジェクトの雛形をカスタマイズする

私は Java コードを書くのに Eclipse を使っています。以前はプロジェクト形式として標準の Java Project を選択していましたが 現在は Gradle プロジェクト形式を選択するようにしています。

Gradle の素晴らしさを知ったのは Android アプリケーションの開発で Android Studio に触れた折でした Android Studio のプロジェクト形式は Gradle プロジェクト形式だったのです。以来 Android 以外の Java アプリケーション開発 Web サーバーアプリや JavaFX アプリ でも Gradle プロジェクト形式を採用するようになりました。

今回は Gradle プロジェクトの雛形をカスタマイズする方法を紹介します。

それでも私は Eclipse を続けるよ!

ちなみに Android Studio IntelliJ IDEA がベースになっています。Android 以外の Java アプリケーション開発環境も Eclipse から IntelliJ IDEA に変えてしまったほうが楽かな?と考えたりもしたのですが 悩んだ末に 長年愛用している Eclipse を使い続けることにしました。

IntelliJ IDEA に乗り換えなかった理由は製品が有償だったことです。IntelliJ IDEA には無償で使えるオープンソースの Community 版もあります。Community 版は個人利用だけでなく商用利用も認められています。それでも 私は 有償の Ultimate 版と無償の Community 版の 2 つが存在していることが気になりました。IntelliJ IDEA Community 版では一部の機能が使えないという差別化が図られています。それがどうしても好きになれなかったのです。

Buildship

話を戻しましょう。

2015 年にリリースされた Eclipse 4.5 MARS から Buildship という Gradle プラグインが標準で含まれるようになりました。すぐに Gradle プロジェクトを使い始めることができます。

Eclipse の標準プロジェクト形式 Java Project を作成する場合は NewJava Project を選択しますよね。

Gradle プロジェクト形式を作成する場合は Java Project ではなく Project... を選択します。

ウィザードが表示されるので Gradle Project を選択して Next > を押します。

ウィザードを最後まで進めていくと プロジェクトの雛形が自動的に作成されます。

この自動的に作成される Gradle プロジェクトは私の好みではないです。

  • build.gradle で指定されているプラグインが java-library になっている。ライブラリよりアプリケーションを開発することのほうが多いので java になっていて欲しい。

  • build.gradle の依存ライブラリに guava が入っている。Google 推しやめてください。

  • サンプルとして初期配置されている Library.java クラス すぐに消してしまうだけなので 最初からないほうがいいです。

  • test フォルダーも要らないです。こんなこと言ったらテストコード書いてないのか!と怒られそうですが…

もっと自分好みの雛形を出力して欲しい! そう思いますよね?

Gradle プロジェクトの雛形をカスタマイズする

というわけで 自動作成される Gradle プロジェクトの雛形をカスタマイズすることにしました。

Gradle プロジェクトの雛形は Eclipse Buildship プラグインが出力しているわけではなく Gradle 自身が出力しています。Buildship を使わずにコマンドラインで gradle init を実行した場合も同じ雛形が出力されます。Buildship が特別なことをしているわけではないので Gradle 自体の機能でプロジェクトの雛形をカスタマイズする方法を考えます。

init.gradle

Gradle にはビルドプロセスをカスタマイズするための init.gradle という仕組みが用意されています。ユーザーフォルダー直下の .gradle フォルダーに init.gradle というファイル名で Gradle ファイルを置いておくと ビルドプロセスの前に init.gradle が実行されるようになります。

Windows の場合 配置パスは %USERPROFILE%¥.gradle¥init.gradle になります。

この仕組みを使って あらかじめ用意しておいた雛形ファイル群がプロジェクトにコピーされるようにします。

init.gradle
buildFinished { Task init = rootProject.tasks.findByName('init') if(init && init.state.executed && !init.state.skipped) { if(init.type.contains('java')) { //delete files ["src/test", "src/main/java/${rootProject.name}"] .each { println "delete ${it}" delete rootProject.file(it) } } //copy files copy { from "templates/${init.type}" into rootProject.file('.') } } if(rootProject.tasks.findByName('nothing')) { copy { from "templates/.gitignore" into rootProject.file('.') } } }

私は このような init.gradle スクリプトを用意しました。

init.gradle はビルドプロセスで常に実行されることに注意してください。新規プロジェクトの作成時 init タスク実行時 だけ雛形のコピーがおこなわれるように if 文の条件を init.state.executed !init.state.skipped としています。

この init.gradle スクリプトでは以下の 3 つの処理をおこなっています。

  • java プロジェクトだったら test フォルダーを削除します。怒らないで!

  • init.gradle と同じ場所にある templates/${init.type} フォルダー内のファイルをプロジェクトにコピーします。${init.type} の部分は gradle init --type 引数で指定された値 プロジェクトのタイプ名 に置き換えられます。Buildship からプロジェクトを作成した場合は java-library が指定されるので templates/java-library 配下のファイルがプロジェクトにコピーされます。

  • nothing タスクが実行された場合に templates/.gitignore をプロジェクトにコピーします。この処理の詳細については後述します。

templates/java-library フォルダーには build.gradle javadoc.css lib を置きました。

  • %USERPROFILE%
    • .gradle
      • init.gradle
      • templates
        • .gitignore
        • java-library
          • build.gradle
          • javadoc.css
          • lib

私が雛形として使っている build.gradle がこれです。

build.gradle
apply plugin: 'java' def defaultEncoding = 'UTF-8' tasks.withType(AbstractCompile).each { it.options.encoding = defaultEncoding } tasks.withType(GroovyCompile).each { it.groovyOptions.encoding = defaultEncoding } javadoc { options.charSet = defaultEncoding options.encoding = defaultEncoding options.stylesheetFile = new File(rootDir, 'javadoc.css') } repositories { jcenter() } dependencies { compile fileTree(dir: 'lib', includes: ['**/*.jar'], excludes: ['**/*-sources.jar', '**/*-javadoc.jar']) }

文字コードの指定 Javadoc スタイルシートの指定 lib フォルダー内の JAR ファイルを参照ライブラリとして追加するようにしています。

init.gradle と雛形ファイル一式は以下のリンクからダウンロードできます。

gradle-init-template-sample.zip (7KB)

Buildship から Gradle プロジェクトを作成してみる

ユーザーフォルダー直下の .gradle フォルダーに init.gradle templates をコピーした状態で Eclipse Gradle プロジェクトを新規作成してみます。

今度は以下のような構成でプロジェクトが作成されました。

  • test フォルダーや Library.java が存在していない。
  • javadoc.css が配置されている。
  • build.gradle の中身がカスタマイズ版に置き換わっている。
  • .gitignore がカスタマイズ版に置き換わっている。Eclipse のエクスプローラービューには表示されていません

これで Gradle プロジェクト新規作成後の定型的なカスタマイズ作業を減らすことができますね。ぜひ 自分好みのプロジェクトの雛形にカスタマイズしてみてください!

.gitignore

Git を使っていない人は読み飛ばして構いません。

.gitigonore Git リポジトリーへの登録を除外するファイルやフォルダーを記述するリストです。このファイルに Eclipse 固有の管理ファイル .classpath .project .settings を追加しておけば Git リポジトリーに Eclipse 固有の管理ファイルが格納されることはなくなり 純粋な Gradle プロジェクトのみを Git リポジトリーに格納することができます。

Eclipse Buildship プラグインはとても賢く build.gradle dependencies 設定から自動的に Eclipse のライブラリ参照を構成してくれるので Eclipse のプロジェクト管理ファイルを大事に守る必要はありません。Buildship プラグインなら いつでも Gradle プロジェクトから Eclipse のプロジェクトを再構成できます。

とても便利な .gitignore ファイルですが このファイルは Gradle でも特別扱いされており templates/java-library .gitignore を配置しておいても新規プロジェクトにコピーされません。

なぜかというと init.gradle buildFinished リスナーで .gitignore をコピーしても その後で Gradle によって .gitignore が勝手に上書きされてしまうからです。この強制上書きは GitIgnoreGenerator というクラスでおこなわれています。

GitIgnoreGenerator.java のソースコード 結構ひどいコードだと思います。

GitIgnoreGenerator.java
public class GitIgnoreGenerator implements BuildContentGenerator { @Override public void generate(InitSettings settings) { File file = fileResolver.resolve(".gitignore"); try { PrintWriter writer = new PrintWriter(new FileWriter(file)); try { writer.println("# Ignore Gradle project-specific cache directory"); writer.println(".gradle"); writer.println(); writer.println("# Ignore Gradle build output directory"); writer.println("build"); } finally { writer.close(); } } catch (IOException e) { throw new UncheckedIOException(e); } } }

外部リソースを元に .gitignore を作るのではなく ソースコードに .gitignore に書き込む中身がハードコーディングされているという…。さらに この BuildContentGenerator インターフェースの呼び出し工程も追いかけてみましたが ファクトリーパターンになっているわけでもなく GitIgnoreGenerator の振る舞いを抑制したり差し替えたりするのは困難に見えました。

Gradle のエンジニアさんでも こんなテキトーなコード書くんですね…。

というわけで gradle init でプロジェクトを新規作成したときに 独自の .gitignore に置き換えることは 通常の方法では できませんでした。

しかし 幸運なことに Eclipse から Buildship Gradle プロジェクトを作成した場合は gradle init だけでなく そのあとで gradle nothing というビルドプロセスも呼び出されるようなのです。

そこで init.gradle に以下のコードを追加しました。

if(rootProject.tasks.findByName('nothing')) {
	copy {
		from "templates/.gitignore"
		into rootProject.file('.')
	}
}

このコードは前述した GitIgnoreGenerator よりも後で呼び出されるため Gradle によって強制上書きされた .gitignore をさらに上書きできます。上書き返し大成功です。

この templates/.gitignore のコピーは Buildship から Gradle プロジェクトを作成した場合のみ有効です。コマンドラインから gradle init を実行した場合は デフォルトの .gitignore のままになってしまうのでご注意ください。

gradle init で自動作成されるプロジェクトの雛形をカスタマイズする方法の紹介は以上です。

この記事を共有しませんか?