Skip to content

JSR-330との互換性

Koinは、Koin AnnotationsとKotlinコンパイラプラグインを通じて、JSR-330 (Jakarta Inject) との完全な互換性を提供します。これにより、KoinはHilt、Dagger、またはその他のJSR-330互換フレームワークから移行するチームにとって優れた選択肢となります。

なぜJSR-330なのか?

JSR-330は、Java/Kotlinにおける依存性注入(Dependency Injection)のための標準的なアノテーションセットを定義しています。

JSR-330 アノテーションKoinでの対応目的
@Injectコンストラクタ検出インジェクト可能なコンストラクタをマークする
@Singleton@Singleシングルインスタンスのスコープ
@Named@Named文字列ベースの修飾子(Qualifier)
@Qualifier@Qualifierカスタム修飾子アノテーション
@Scope@Scopeカスタムスコープアノテーション

セットアップ

プロジェクトに koin-jsr330 の依存関係を追加します。

kotlin
dependencies {
    implementation("io.insert-koin:koin-jsr330:$koin_version")
}

基本的な使い方

@Singleton と @Inject

既存のHilt/DaggerクラスをそのままKoinで利用できます。

kotlin
import jakarta.inject.Inject
import jakarta.inject.Singleton

@Singleton
class UserRepository @Inject constructor(
    private val api: ApiService,
    private val database: UserDatabase
)

@Singleton
class ApiService @Inject constructor(
    private val httpClient: OkHttpClient
)

@Named 修飾子

文字列ベースの修飾子(Qualifiers)も同様に動作します。

kotlin
import jakarta.inject.Named
import jakarta.inject.Singleton

@Singleton
@Named("api")
class ApiOkHttpClient @Inject constructor() : OkHttpClient()

@Singleton
@Named("image")
class ImageOkHttpClient @Inject constructor() : OkHttpClient()

@Singleton
class NetworkManager @Inject constructor(
    @Named("api") private val apiClient: OkHttpClient,
    @Named("image") private val imageClient: OkHttpClient
)

カスタム @Qualifier アノテーション

既存のカスタム修飾子をそのまま保持できます。

kotlin
import jakarta.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IoDispatcher

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MainDispatcher

@Singleton
class CoroutineModule {
    @IoDispatcher
    fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO

    @MainDispatcher
    fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
}

@Singleton
class DataSyncManager @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher
)

Android ViewModel

JSR-330アノテーションは、KoinのViewModelサポートと組み合わせて動作します。

kotlin
import jakarta.inject.Inject

@KoinViewModel
class UserViewModel @Inject constructor(
    private val userRepository: UserRepository,
    private val savedStateHandle: SavedStateHandle
) : ViewModel() {

    fun loadUser(id: String) {
        viewModelScope.launch {
            val user = userRepository.getUser(id)
            // ...
        }
    }
}

NOTE

ViewModelには @KoinViewModel(Koinのアノテーション)を使用してください。JSR-330ではViewModel用のアノテーションは定義されていません。

Hiltからの移行

移行前 (Hilt)

kotlin
@HiltAndroidApp
class MyApplication : Application()

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject lateinit var analytics: Analytics
}

@Singleton
class Analytics @Inject constructor(
    @ApplicationContext private val context: Context
)

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideRetrofit(): Retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com")
        .build()
}

移行後 (Koin と JSR-330)

kotlin
// Application - startKoin を使用
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@MyApplication)
            modules(appModule)
        }
    }
}

// Activity - by inject() を使用
class MainActivity : AppCompatActivity() {
    private val analytics: Analytics by inject()
}

// @Singleton と @Inject は変更不要です!
@Singleton
class Analytics @Inject constructor(
    private val context: Context  // KoinがContextを自動的に提供します
)

// インスタンス提供用の @Single を伴うモジュール
@Module
@ComponentScan
class NetworkModule {
    @Single
    fun provideRetrofit(): Retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com")
        .build()
}

混在した使用

同じプロジェクト内で、JSR-330とKoinのアノテーションを自由に混在させることができます。

kotlin
// JSR-330 スタイル
@Singleton
@Named("local")
class LocalDatabase @Inject constructor() : Database

// Koin スタイル
@Single
@Named("remote")
class RemoteDatabase(private val api: ApiService) : Database

// 混在 - JSR-330 によるインジェクションを伴う Koin アノテーション
@Factory
class DatabaseManager @Inject constructor(
    @Named("local") private val local: Database,
    @Named("remote") private val remote: Database
)

コンパイラプラグインのサポート

KoinコンパイラプラグインもJSR-330アノテーションを認識します。

kotlin
// これらはコンパイラプラグインにおいて同等です
@Singleton
class UserRepository @Inject constructor(private val api: ApiService)

// コンパイラプラグイン DSL (同じコードを生成します)
val module = module {
    single<UserRepository>()
}

メリット

  • コード変更が不要 - 既存の @Inject@Singleton アノテーションがそのまま動作します。
  • 段階的な移行 - HiltとKoinを混在させながら、モジュールごとに移行できます。
  • 標準への準拠 - JSR-330はJava/Kotlinの標準であり、特定のフレームワークに依存しません。
  • チームの習熟度 - 開発者はHilt/Daggerを通じてこれらのアノテーションに慣れています。
  • ツールのサポート - IDEがJSR-330アノテーションをサポートしています。

制限事項

いくつかのHilt固有の機能には、直接対応するJSR-330の同等機能がありません。

Hilt の機能Koin でのアプローチ
@HiltAndroidApp@KoinApplication + Application内での startKoin<T>{}
@AndroidEntryPointby inject() 拡張関数
@HiltViewModel@KoinViewModel
@ApplicationContextContext パラメータ (自動インジェクト)
@ActivityContextスコープベースのコンテキスト解決

次のステップ