とある既存の Java の (SplingBoot) プロジェクトを Kotlin に移植中、突如 build が通らない現象が起こりまして。
なんでかなー?
Kotlin 的には Getter を class に差し込むし、この記述で Private な訳ないんだけどなー?
という現象に引っかかったので久々の技術メモを。
結論としては、 Gradle の Java plugin と Kotlin plugin と Lombok の中がよろしくないということのようで
- Kotlin は compileJava が dependsOn されているので先に compileJava が走る。
- その後に compileKotlin される。
- 結果、参照している Lombok で実装しているクラスのメンバは Delombok される前なのですべて Private なので当然エラーになる。
という流れでした。
状況を説明するためのテストコードとしてはこんな感じです。
ことの発端になったログはこんな感じでした。
$ ./gradlew build
:compileKotlin
e: /home/hoge/repos/LombokConflict/src/main/kotlin/Application.kt: (3, 15): Cannot access 'id': it is 'private' in 'DataModel'
e: /home/hoge/repos/LombokConflict/src/main/kotlin/Application.kt: (4, 15): Cannot access 'description': it is 'private' in 'DataModel'
:compileKotlin FAILED
FAILURE: Build failed with an exception.
@Data 指定してあるし、Getterいるしなんでだろう?
と思ったので、
DeLombok したコードの状態で build すると
$ ./gradlew build
:compileKotlin
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestKotlin UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
Total time: 8.041 secs
Google翻訳「成功したビルド」
Compile が通るんですよ。
で、こりゃ gradle の流れがおかしいか?と思って調べてみた結果。
http://stackoverflow.com/questions/35517325/kotlin-doesnt-see-java-lombok-accessors
唯一の回避策としてはコンパイル順序を制御することだ、とありますが上のとおり Gradle の pulugin 経由だともはやどうしようもなさそうです。
公式でも同じ内容があって、
なんか似たようなこと言ってますね。
module を分けるなどをすれば問題ない。
論理的根拠は Kotlin はバイトコードからそれらを参照するが Lombok は On the fly でそれらを生成する。
だそうで。
PreCompiler と PostCompiler の違い、と言ってしまえばそれまでな気はしますし、だからといってお互いに修正する方向には来ないんだろうなーという気もしています。
結局、既存プロジェクトを Kotlin へ順次移行するのは Lombok と衝突する。
似たもの同士、近くによるとロクなことがない、という人生教訓になりましたとさ。
めでたくないです。つらいです。
ということで、 Java 、とくに SpringBoot で作られた既存のプロジェクトを Kotlin に移植するのは一気にやるか、またはサブプロジェクトとスコープを調整し直すかなにかしないといけませんよ、ということのようです。
特に Annotation もりもりの SpringBoot の移植はそれなりの規模になると、ちょっと気合入れて手を入れないと厳しそうな感じでしょうか。
今回のソースコード一式はこちら。
https://github.com/grim13b/LombokConflict
コメント
コメントを投稿