I had the "typical" issue of dependency cycle error trying to make a call to refresh token in an Interceptor. I found some related questions and answers, specially this one and this one. I followed them and it made the code compiling.
But it doesn't work because the 'ServiceHolder' is always empty (created without the service), so I guess I'm doing something wrong with Dagger and I don't know what.
I have the 'AuthServiceHolder':
class AuthServiceHolder {
internal var authService: AuthService? = null
fun get(): AuthService? {
return authService
}
fun set(authService: AuthService) {
this.authService = authService
}
}
I have the 'TokenExpiredInterceptor' (first lines):
@TokenExpiredInterceptorScope
class TokenExpiredInterceptor @Inject constructor(private val authServiceHolder: AuthServiceHolder
) : Interceptor
I try to get the service to make the call but is always null in 'TokenExpiredInterceptor':
val authService = authServiceHolder.get()
I have 2 instances of retroft, one for a legacy API and another for the new API. The common module is:
@Module
object CommonApiModule {
@JvmStatic
internal fun retrofitBuilder(okHttpClient: OkHttpClient, baseUrl: HttpUrl) = Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
(...)
}
The module where I create the retrofit for the new API is:
@Module
class MyMicroservicesApiModule(baseUrl: String) : BaseApiModule(baseUrl) {
@Provides
@ForNetworkApi(NetworkApiType.MY_MICROSERVICES)
@NetworkScope
internal fun retrofit(okHttpClient: OkHttpClient,
callAdapterFactory: RxJava2CallAdapterFactory,
moshi: Moshi): Retrofit =
CommonApiModule.retrofitBuilder(okHttpClient, httpUrl)
.addCallAdapterFactory(callAdapterFactory)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
}
The module with the interceptor is:
@Module(includes = [
(...)
])
abstract class AuthTokenBindingsModule {
@Binds
@IntoSet
@ForNetworkInterceptors
internal abstract fun tokenExpiredInterceptor(tokenExpiredInterceptor: TokenExpiredInterceptor): Interceptor
(...)
@Module
companion object {
(...)
@Provides
@JvmStatic
@NetworkScope
fun authServiceHolder(): AuthServiceHolder = AuthServiceHolder()
}
}
The module for create the httpClient is:
@Module(includes = [HttpInterceptorsModule::class])
object HttpModule {
private const val CONNECTION_TIMEOUT = 25
private const val READ_CONNECTION_TIMEOUT = 25
private const val WRITE_CONNECTION_TIMEOUT = 25
private const val DISK_CACHE_SIZE: Long = 50 * 1024 * 1024
@JvmStatic
@Provides
@NetworkScope
internal fun httpClient(application: Application,
@ForNetworkInterceptors networkInterceptors: Set<@JvmSuppressWildcards Interceptor>,
@ForHttpInterceptors httpInterceptors: Set<@JvmSuppressWildcards Interceptor>): OkHttpClient {
val builder = httpClientBuilder(application)
httpInterceptors.forEach { it -> builder.addInterceptor(it) }
networkInterceptors.forEach { it -> builder.addNetworkInterceptor(it) }
if (BuildConfig.DEBUG) {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
builder.addNetworkInterceptor(loggingInterceptor)
}
return builder.build()
}
@JvmStatic
private fun httpClientBuilder(application: Application): OkHttpClient.Builder {
val builder = OkHttpClient.Builder()
.connectTimeout(CONNECTION_TIMEOUT.toLong(), TimeUnit.SECONDS)
.readTimeout(READ_CONNECTION_TIMEOUT.toLong(), TimeUnit.SECONDS)
.writeTimeout(WRITE_CONNECTION_TIMEOUT.toLong(), TimeUnit.SECONDS)
val cacheDir = File(application.cacheDir, "http")
val cache = Cache(cacheDir, DISK_CACHE_SIZE)
builder.cache(cache)
return builder
}
}
Finally, my network component is:
@NetworkScope
@TokenExpiredInterceptorScope
@AuthenticatorScope
@Component(modules = [
(...)
CommonApiModule::class,
MyMicroservicesApiModule::class,
AuthTokenBindingsModule::class,
(...)
], dependencies = [AppServiceProvider::class])
interface NetworkComponent :
(...)
MyMicroservicesApiProvider,
(...) {
With this code I have an instance of 'AuthServiceHolder' in the 'TokenExpiredInterceptor', it is NOT null but it is empty. I saw in the links above I have to refactor the 'AuthService' provider with something like this:
@Provides
@NetworkScope
internal fun authService(@ForNetworkApi(NetworkApiType.MY_MICROSERVICES) retrofit: Retrofit, authServiceHolder: AuthServiceHolder): AuthService {
val authService = retrofit.create(AuthService::class.java)
authServiceHolder.set(authService)
return authService
}`
But I don't know where put it. I've tried in 'AuthTokenBindingsModule', in 'MyMicroservicesApiModule', with no success, it is always empty.
I've omitted several lines of code to make it simpler and for privacy.
Any idea? Thanks in advance.