はじめに (対象読者・この記事でわかること)
この記事は、Javaで構築された既存システムをKotlinに段階的に移行したいエンジニアを対象にしています。Java歴はあるがKotlinの経験はまだ浅い、あるいは「全部Kotlinで書き直す」ことがリスクに思える方向けです。
記事を読むことで、JavaコードをKotlinに変換する際の具体的な手順、自動変換ツールの活用法、ビルド設定の変更ポイント、そして移行を安全に進めるためのテスト戦略が身につきます。サンプルリポジトリを使いながら、実際の移行作業で起こりがちな落とし穴とその回避方法も共有します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - Java 11以上の言語仕様と基本的なビルド手順(Maven/Gradle) - IntelliJ IDEAまたはAndroid Studioの基本的な操作 - JUnit 5を使った単体テストの書き方 - Gitを使ったブランチ運用の基礎
Java→Kotlin移行が加速する背景
2021年にGoogleが「Kotlinファースト」を表明して以降、Android新規プロジェクトの8割以上がKotlinを採用しています。サーバーサイドでもSpring Boot 3.xはKotlinコルーチンをネイティブサポートしており、Javaコードベースをそのまま放置しておく機会損失は年々大きくなっています。
しかし「全部一気に書き換える」は現実的ではありません。既存のビジネスロジックを動かしながら、新規機能からKotlinで書き始め、徐々に移行していく「段階的移行戦略」が求められます。本記事では、実際にプロダクションで使われているJavaマルチモジュールプロジェクトを題材に、移行を成功に導くノウハウをお届けします。
実践:GradleマルチモジュールをJava→Kotlinに移行する
ステップ1:Kotlin対応をGradleに追加 & 自動変換で90%を一気に変換
まずは既存のJavaモジュールにKotlinを混在させるための最小構成をbuild.gradleに追加します。
Gradleplugins { id 'java-library' id 'org.jetbrains.kotlin.jvm' version '1.9.24' } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testImplementation "org.jetbrains.kotlin:kotlin-test-junit5" } compileKotlin { kotlinOptions.jvmTarget = "17" }
次にIntelliJの「Code → Convert Java File to Kotlin File」(ショートカット:Ctrl+Alt+Shift+K)を使います。
注意点として、変換前に必ず「Gitのローカルブランチを切る」ことです。自動変換でも@Nullableアノテーションが?に、ラムダがトレーリングラムダに、Getter/Setterがプロパティに変換されるため、差分が大量に発生します。
変換後は即座にビルドしてコンパイルエラーを洗い出します。ほとんどのケースで「varになってしまったが実質val」「lateinit varにすべきフィールド」などが見つかるため、手動でリファクタリングします。
ステップ2:Spring Bootモジュールを例に、相互運用の落とし穴を回避する
Javaの@ComponentとKotlinの@Componentが混在してもSpringは問題なく動作しますが、次の2点でハマりどころがあります。
-
アノテーションの配列属性をKotlinで書くとき
Javaでは@RequestMapping(path = {"api/v1","api/v2"})ですが、Kotlinでは配列リテラルが必要です。
kotlin @RequestMapping(path = ["api/v1", "api/v2"]) -
Lombokとの同居
LombokはKotlinでは動作しないため、データクラスに置き換えます。
Java:java @Data @Builder public class UserDto { ... }Kotlin:kotlin data class UserDto( val id: Long, val name: String, ... ) { class Builder { ... } // 必要に応じて実装 }
ハマった点:テストコードの移行でMockkとMockitoが混在してCIが落ちる
移行初期に「KotlinのテストはMockkにしよう」と方針を決めてしまうと、Javaテストが残っている間はMockitoのスタブが効かなくなり、CIで確実に失敗します。
特にgiven(...).willReturn(...)がKotlinではgivenのインポート競合でコンパイルエラーになるケースが多発しました。
解決策:段階的にテストケースを移行するための「移行用ラッパー」を用意
- モジュール内に
src/test/javaとsrc/test/kotlinを共存させる。 - 新規テストはKotlin+Mockkで書くが、既存Javaテストを触らない。
- Mockitoの静的インポートを避けるため、拡張関数を用意:
kotlin fun <T> whenever(call: T): OngoingStub<T> = Mockito.`when`(call) - CIで
./gradlew testを実行したときに、両方のエンジンが動作するようにtestタスクにuseJUnitPlatform()を明示。
これにより、移行途中でもCIがグリーンを保ちながら、1クラスずつKotlinに書き換えられるようになります。
まとめ
本記事では、JavaマルチモジュールをKotlinに段階移行する際の実践的な手順を紹介しました。
- IntelliJの自動変換で90%を一気に変換し、残りを手動でリファクタリング
- Spring Boot+LombokのコードをKotlinのプロパティ/データクラスに置き換えるポイント
- MockitoとMockkが混在してもCIをグリーンに保つ「移行用ラッパー」戦略
この記事を通して、移行作業を「大きく巻き戻すリスクなし」で進められる体制が整えられるはずです。
次回は「移行後のパフォーマンス検証」「Kotlin DSLへのビルドスクリプト移行」について深掘りします。
参考資料
