Kotlin の kapt を IntelliJ IDEA で動かしたい (Gradle プロジェクト)

手探りでいろいろ試したり調べたりしていきついた方法を書いてます。 もっといい方法がある気がするからなんかあったら教えてください。 (Android Studio における Android アプリ開発だと kapt をもっといい感じに扱えてる気がするけどそっちについては特に調べてない。)

# まとめ

* Kotlin 1.0.5-2 時点では IntelliJ IDEA による直接の kapt サポートはないぽい。
    * IntelliJ IDEA 2016.3、Kotlin plugin 1.0.5-release-IJ2016.3-2 で試した。
* JetBrains の人的には 「Gradle プロジェクトなら **Gradle タスクを実行して kapt を使ってね**」 という感じっぽい。
* IntelliJ IDEA から Gradle タスクを実行する方法としては以下のようなものがある。
    * Gradle ツールウィンドウなどから明示的にタスクを実行する。
    * ビルド実行前に指定の Gradle タスクを実行するように設定する。
    * IntelliJ IDEA におけるビルドや実行を全て Gradle に委譲するように設定する。
* Gradle タスクによる kapt で生成されたソースコードを IntelliJ IDEA が認識できるように設定しよう。

# 背景

先日、Dagger 2 を使っている Java プロジェクトを IntelliJ IDEA でビルドする (アノテーションプロセッシングも行う) 方法についてまとめた。

* [IntelliJ IDEA / Gradle 環境の Java プロジェクトで Dagger 2 (Google Dagger) を使う方法メモ](http://qiita.com/nobuoka/items/e18f9a03c0a281ed73c1)

このプロジェクトに Kotlin を導入して、Kotlin のアノテーションプロセッシングツール kapt を使って Gradle でのビルドは問題なくできるようになったものの、IntelliJ IDEA にていい感じに扱う方法がわからなかったので調べた。

# 現時点では IntelliJ IDEA (および Kotlin Plugin) による直接の kapt サポートはない

ないらしい。 JetBrains の人が言ってる。

> **Raman.Gupta** :
> How can I get the Kotlin annotation processor to run from IJ?
> "Enable annotation processors" in Settings does not seem to work.
>
> **yole** (JetBrains Team) :
>This is currently unsupported. What's your use case? Why can't you use Gradle to build your project?

(「[Execute kapt/kapt2 from within IJ - Kotlin Discussions](https://discuss.kotlinlang.org/t/execute-kapt-kapt2-from-within-ij/2006)」 より)

Gradle でビルドできないん？ って言ってるから JetBrains の人的には Gradle でビルドするのが普通っぽい？

# というわけで Gradle タスクを使う

## IntelliJ IDEA から Gradle タスクを実行する方法

IntelliJ IDEA で Gradle タスクを実行する方法を 3 つ書いておく。 IntelliJ IDEA 2016.3 時点での設定である。

### Gradle ツールウィンドウから明示的に実行する

Gradle ツールウィンドウから、「Tasks」 → 「build」 → 「assemble」 を選択して実行すれば kapt も走る。 ショートカットキーも設定できるので、開発中に何度も明示的に実行するならショートカットキーを割り当てておくとよい。

### ビルド前に指定の Gradle タスクを実行するように設定する

Gradle ツールウィンドウから、「Tasks」 → 「build」 → 「assemble」 を右クリックし、「Execute Before Build」 を有効にすると、IntelliJ IDEA でビルドする際に Gradle の `assemble` タスクが実行されるようになる。 IntelliJ IDEA 側と Gradle 側で二重にビルドが走ってしまうのがつらいところではあるが、kapt が有効になる。

毎回明示的に実行するのは面倒なので、自分は今のところこの方法を使っている。

### ビルドと実行を Gradle に委譲するように設定する

設定の 「Build, Execution, Deployment」 → 「Build Tools」 → 「Gradle」 → 「Runner」 で 「Delegate IDE build/run actions to gradle」 にチェックを入れる。

これで問題なく開発できるならこれが一番まともな気がする？ 自分のプロジェクト (web アプリケーション) では、「実行中のプロセスを再実行した際に、再実行前のプロセスの終了に時間がかかっていて、同じポートにバインドしようとしてエラーになってしまう」 という問題があったのでこの方法は採らないことにした。

## 生成されるソースコードをソースフォルダとして追加しよう

あと、Gradle タスクによる kapt で生成されたソースコードを IntelliJ IDEA が認識できるように設定する必要がある。 「Project Structure」 からモジュールを選択し、「build/generated/source/kapt/main」 をソースディレクトリとして追加しよう。 (テストでも kapt を使う場合はテストの方も。) kapt 2 を使っている場合は 「kapt」 の部分が 「kapt2」 になる。

ちなみに IntelliJ IDEA 2016.1 からは、デフォルトでソースセットごとにモジュールが分かれているので、「Add Content Root」 でディレクトリごと content root として追加する必要がある。 (プロジェクトのインポート時に 「Create separate module per source set」 のチェックを外していれば、普通にディレクトリを選択するだけでいけるはず。)

![intellij.png](https://qiita-image-store.s3.amazonaws.com/0/5721/8ad31bdb-e9f1-bf72-e4d6-245933848ba5.png)

# ちなみに build.gradle はどんなん？

今更だけど build.gradle を貼っておく。 以下のような build.gradle を書けば Kotlin を使ったプロジェクトで Dagger を使えるはず。

```groovy
buildscript {
    ext.kotlin_version = '1.0.5-2'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'java'
apply plugin: 'kotlin'

group 'com.example.kotlin.kapt'
version '1.0-SNAPSHOT'

sourceCompatibility = 1.8
targetCompatibility = 1.8

def defaultEncoding = 'UTF-8'
tasks.withType(JavaCompile)*.options*.encoding = defaultEncoding

repositories {
    mavenCentral()
}

sourceSets {
    main.java.srcDirs += 'src/main/kotlin'
}

kapt {
    generateStubs = true
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

    compile 'com.google.dagger:dagger:2.8'
    kapt 'com.google.dagger:dagger-compiler:2.8'
}
```

# その他参考にしたページ

kapt 周りがよくわかんなかったので調べたときに参考になったページ。

* [Better Annotation Processing: Supporting Stubs in kapt | Kotin Blog](https://blog.jetbrains.com/kotlin/2015/06/better-annotation-processing-supporting-stubs-in-kapt/) : kapt の stub の話。 JetBrains の公式ブログ。
* [kapt の generateStubs と DI ツールとの関係](http://qiita.com/laprasDrum/items/417b48972ddefdc3b2cd) : Kotlin で Dagger を使う例を挙げながら kapt の仕組みを説明。 わかりやすい。
* [How can I get Kotlin working Dagger 2 and Intellij for non-android projects? - Kotlin Discussions](https://discuss.kotlinlang.org/t/how-can-i-get-kotlin-working-dagger-2-and-intellij-for-non-android-projects/1572) : kapt が生成したソースファイルを InnteliJ IDEA が認識しないという問題。
    * 解決策として build.gradle にソースディレクトリの設定を追加する方法が書かれてる。 個人的には IDE のための設定をプロジェクトに持たせたくないから IntelliJ IDEA 側で設定したい。
* [Kotlin 1.0.4 is here | Kotlin Blog](https://blog.jetbrains.com/kotlin/2016/09/kotlin-1-0-4-is-here/) : Kotlin 1.0.4 から実験的に kapt 2 が導入された。
* kapt は JPS (IntelliJ のビルドシステム) ではサポートしてない話。
    * [Execute kapt/kapt2 from within IJ - Kotlin Discussions](https://discuss.kotlinlang.org/t/execute-kapt-kapt2-from-within-ij/2006)
    * [Annotation processing, gradle? - Kotlin Discussions](https://discuss.kotlinlang.org/t/annotation-processing-gradle/1438)