IntelliJ IDEAとGradleタスクでコンパイラの出力先が異なる状態になることがある。自分の場合は、新規プロジェクトを作成して構築中は一致していたのだが、一旦git pushしたものを改めてgit cloneしてからIDEAに取り込んだ際に異なる状態になった。

  • IDEAの出力先:out/productionの配下のclassesresources
  • Gradleの出力先:build配下のclassesresources

ちなみに、classesはソースのコンパイル先であり、resourcesはリソースファイルのコピー先である。
異なると何が問題かというと、gradleで実行したアプリケーションにおいて、ソースコードの変更を検知してAutoReloadしたい場合に、変更を検知できないことである。
ソースコード変更->IDEAでBuild->classファイルをIDEAに出力先に出力->アプリケーションのclass pathはGradleの出力先なので変更を検知できないという流れである。
この問題を回避するために、IDEAとGradleのコンパイラの出力先を一致させる必要がある。

方法1:IDEAの設定で出力先を変更する(部分的にしか解決しない)

IDEAのProject Structure -> Modules -> Paths -> Compiler outputで、Use module compile output pathを選択し、Output pathをGradleの出力先と合わせる。

しかし、この方法だとソースのコンパイル先はbuild/classesになりGradleと一致させられるのだが、リソースファイルの出力先はout/productionのままなので異なったままである。リソースファイルはAutoReload対象にしなくてもいいという人はこの方法で十分かもしれない。

なお、リソースファイルの出力先はIDEA場では個別に指定することはできなそうである(少なくとも自分は発見できなかった)。

ちなみに、Project Structure -> Project -> Project compiler outputプロジェクトパス/buildに変更して、Module -> Paths -> Compiler outputInherit project compile output pathにすることでうまくいきそうなものだが、残念なことにIDEAがbuild/production/のように勝手にproductionフォルダを作ってしまうため、Gardleの出力先と一致させることはできない。

方法2:IDEAでプロジェクト作成時にGradleプロジェクトとして作成する(解決する)

この方法で完全解決することは確認できているのだが、既存プロジェクトを取り込む際には普通はプロジェクトの新規作成は行わないので気づきにくい。
ここではgit cloneした既存プロジェクトを新規作成扱いで取り込む手順を記載する。

  1. git cloneする
  2. Create New Projectを選択する。
    Import ProjectOpenは使わない
  3. Gradleプロジェクトとして作成する
  4. GroupIdArtifactIdに適当な値を設定する。
    GroupIdは適当な値でOK。ArtifactIdは既存プロジェクトの名称と一致させる。
  5. Gradleプロジェクトの設定を行う。
    User auto-importbuild.gradleに変更があったら自動で依存関係などを解決してくれるというやつなので、好みで外してもいいと思う。
    Create separate module per source setmaintestを別モジュールとしてプロジェクトを作成してくれるというものなので、チェックしておいた方が良いと思う。
    Use default gradle wrapperも推奨なので設定しておいた方が良いと思われる。
  6. git cloneしたフォルダと一致するようにProject nameProject locationを設定する
  7. そのまま作成を完了する
  8. 既存プロジェクトからの変更箇所をgit diffで確認する
    矢印の部分が勝手に作成された部分なので、この部分を削除する。
    ちなみに、このプロジェクトでは.gitignore.idea.gradleを設定済みなのでそこは差分として出ていない。もし設定してなかったら設定した方が良い。
  9. 変更箇所を削除する
    git reset --hard masterで一発でやってもいいし、一つ一つ変更を破棄してもいいと思う。
  10. GradleのRefleshが走りProject Buildを実行すると、以下のように意図通りにコンパイル結果が出力される

方法3:Gradleの設定で出力先を変更する(解決する)

おそらくbuild.gradleでGradleタスクのコンパイラ出力先をout/productionに変更するというのも、もう一つの解放になりえると思う。

compileJava {
    buildDir = "out/production"
}
compileKotlin {
    buildDir = "out/production"
}
sourceSets {
    main {
        output.resourcesDir = "out/production/resources"
    }
}

この設定で試して見ると以下のようになる。

  • Gradleタスクのソースコードのコンパイル先:out/production/classes/kotlin/main/sample
  • Gradleタスクのリソースファイルのコンパイル先:out/production/resources

リソースファイルは想定通りだが、よく見るとソースコードの方は余計な階層kotlin/mainができてしまっている。
これを解決するために、IDEAのProject Structure -> Modules -> Paths -> Compiler outputで、Use module compile output pathを選択し、Output path
プロジェクトルート/out/production/classes/kotlin/mainを設定し、Gradleの出力先と合わせる必要がある。

この方法でも出力先を一致させることはできた。
しかし、build.gradleとIDEAの二つの設定が必要になるので、方法2の方がまだマシな気がするので、私自身は方法2を採用した。