はじめに
自分が所属しているプロジェクトでは、Spring Boot を使った Java の Web API を開発しています。
ずっと Java で書かれてきたコードベースですが、「Kotlin って実際どうなの?」という興味から、まずは 1つのアプリケーションサービスを Kotlin に書き換えてみました。
結果から言うと、「思ったよりも簡単に Kotlin を導入できた」です。
本記事ではその手順と気づきを紹介します。
Java 版のコード
まず、既存の Java コードはこちらです👇
package com.example.user.service;
import com.example.user.domain.repository.UserRepository;
import com.example.user.dto.UserDto;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class GetUserService {
private final UserRepository userRepository;
public Optional<UserDto> getById(Long id) {
return userRepository.findById(id).map(UserDto::new);
}
}
よくある Spring Boot のサービスクラスで、UserRepository からユーザー情報を取得して UserDto に変換するシンプルな処理です。
Kotlin に書き換えたコード
Kotlin 版はこちらです👇
package com.example.order.service
import com.example.user.domain.repository.UserRepository
import com.example.user.dto.UserDto
import org.springframework.stereotype.Service
@Service
class GetUserService(
private val userRepository: UserRepository
) {
fun getById(id: Long): UserDto? {
return userRepository.findById(id)
.map { UserDto(it) }
.orElse(null)
}
}
書き換えのポイント
✅ 変わった点
- Optional → nullable (
UserDto?) -
map(UserDto::new)→map { UserDto(it) } -
@RequiredArgsConstructor不要。Kotlin のコンストラクタ引数で依存注入される
🟢 変わらなかった点
- Spring Boot の
@Serviceアノテーションはそのまま利用可能 - 既存の Java 製 UserRepository も変更不要で使えました
呼び出し側の変更(Java → Kotlin の境界)
Kotlin の getById は UserDto?(nullable)を返すため、Java 側から呼び出す場合は Optional に包んであげる必要があります。
// Java 側の変更前
Optional<UserDto> userDto = getUserService.getById(id);
// Java 側の変更後
Optional<UserDto> userDto = Optional.ofNullable(getUserService.getById(id));
Kotlin では null ベース、Java では Optional ベースなので、ここで少し変換が入ります。
とはいえ、一行の変更で済む程度でした。
Kotlin をビルドできるようにする設定
Java プロジェクトに Kotlin ファイルを混ぜるためには、build.gradle.kts に Kotlin プラグインを追加する必要があります。
plugins {
java
kotlin("jvm") version "2.0.21"
}
tasks.named("compileKotlin") {
dependsOn(genInboundWsdl)
dependsOn(genOutboundWsdl)
}
これだけで Kotlin ファイル(.kt)がビルド対象に含まれます。
Java と Kotlin は同じクラスパス上で共存できるため、
既存の Spring Boot プロジェクトにもスムーズに導入できました。
テストコードがほぼそのまま動いた
既存の Java テストコードも、Optional 対応を除けばそのまま動作しました。
@Test
void shouldReturnUserWhenExists() {
Optional<UserDto> result = Optional.ofNullable(getUserService.getById(1L));
assertTrue(result.isPresent());
}
このように、修正は最小限でテストはすべてグリーンのままでした ✅
Kotlin は JVM 上で動作し、Java とのバイナリ互換性が完全に保たれているため、
Kotlin クラスを Java からそのまま呼び出すことができます。
Kotlin と Java の自然な共存
面白いのは、実装は Kotlin、テストは Java という構成も問題なく成立することです。
たとえば、
- 実装側では Kotlin の null 安全や関数型スタイルを活かす
- テスト側では Java の JUnit Mockito をそのまま使う
といった「混在構成」が簡単に実現できます。
そのため、プロジェクト全体を一気に Kotlin に切り替える必要はなく、
書ける人から少しずつ Kotlin に移行していく段階導入が可能です。
まとめ
実際に Kotlin ファイルを1つ追加してみた感想としては、
- Spring Boot のアノテーションはそのまま動く
- Java コードとの相互運用性もほぼ問題なし
- 実装側は Kotlin 、テスト側は Java といった「混在構成」も可能
つまり、「少しずつ Kotlin 化していく」 アプローチが十分現実的だと感じました。
大きなリファクタリングをしなくても、段階的に Kotlin に置き換えていけそうです。