4.3 KiB
Dagger / Hilt Conversion Guide
When This Applies
This guide applies when the Java source contains imports matching dagger.* or
dagger.hilt.*. This covers Dagger 2, Hilt for Android, and Hilt Jetpack integrations.
Key Rules
1. @Inject constructor syntax
Kotlin places @Inject before the constructor keyword in the primary constructor:
class Foo @Inject constructor(private val bar: Bar)
2. @Module classes with @Provides methods
Keep @Provides methods open, or use object for modules that contain only
@JvmStatic provides methods (companion object pattern):
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder().build()
}
3. @Binds abstract methods
@Binds methods work in abstract classes exactly as in Java. Convert the abstract
class directly — no special Kotlin considerations.
4. Hilt Android annotations
@HiltAndroidApp, @AndroidEntryPoint, @HiltViewModel — preserve these exactly
on Application, Activity, Fragment, and ViewModel classes.
5. Scoping annotations
@Singleton, @ActivityScoped, @ViewModelScoped, @FragmentScoped — preserve
exactly. No annotation site target is needed.
6. @AssistedInject / @AssistedFactory
@AssistedInject replaces @Inject on the constructor. @Assisted parameters
appear alongside regular injected parameters in the primary constructor:
class PlayerViewModel @AssistedInject constructor(
@Assisted private val playerId: String,
private val repository: PlayerRepository
) : ViewModel()
7. @Component / @Subcomponent interfaces
Convert directly to Kotlin interfaces. Dagger's annotation processing works identically with Kotlin interfaces via kapt or KSP.
Examples
Example 1: Hilt ViewModel with @Inject Constructor and a @Module
Java:
package com.acme.feature;
import androidx.lifecycle.ViewModel;
import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.android.lifecycle.HiltViewModel;
import dagger.hilt.components.SingletonComponent;
import javax.inject.Inject;
import javax.inject.Singleton;
@HiltViewModel
public class UserProfileViewModel extends ViewModel {
private final UserRepository userRepository;
private final AnalyticsTracker analyticsTracker;
@Inject
public UserProfileViewModel(UserRepository userRepository, AnalyticsTracker analyticsTracker) {
this.userRepository = userRepository;
this.analyticsTracker = analyticsTracker;
}
public LiveData<User> getUser(String userId) {
analyticsTracker.trackProfileView(userId);
return userRepository.getUser(userId);
}
}
@Module
@InstallIn(SingletonComponent.class)
public class AnalyticsModule {
@Provides
@Singleton
public AnalyticsTracker provideAnalyticsTracker(Application app) {
return new AnalyticsTracker(app);
}
}
Kotlin:
package com.acme.feature
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.components.SingletonComponent
import javax.inject.Inject
import javax.inject.Singleton
@HiltViewModel
class UserProfileViewModel @Inject constructor(
private val userRepository: UserRepository,
private val analyticsTracker: AnalyticsTracker
) : ViewModel() {
fun getUser(userId: String): LiveData<User> {
analyticsTracker.trackProfileView(userId)
return userRepository.getUser(userId)
}
}
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {
@Provides
@Singleton
fun provideAnalyticsTracker(app: Application): AnalyticsTracker {
return AnalyticsTracker(app)
}
}
Key changes:
@Injectmoves before theconstructorkeyword in the primary constructor.- Constructor parameters become
private valin the primary constructor. - The module class becomes an
objectsince it contains only static-like provides methods. SingletonComponent.classbecomesSingletonComponent::class(Kotlin class reference).- Java getter method
getUserbecomes a regular functiongetUser(nogetprefix convention change needed here since it takes a parameter).