Search code examples
javakotlindagger-2

Kotlin List vs java.util.List generic type inside Java code


I'm stuck with strange behavior while migrating my project to kotlin.

It's occurred while i tried to generate dagger injectors. The problem in java or dagger, someone can't resolve kotlin List from generic type

Example:


interface CacheEntity<Result> {
  fun onResult(result: Result)
  fun getUpdatableData(): Observable<Result>
}
class CacheRepository< Result, Entity:CacheEntity<Result> >(
  val entity: Entity) {

   // do some operations with Entity
   fun doSome() {
     entity.getUpdatableData()
     entity.onResult(...)
   }
}
class UserRepository: CacheEntity<User> {
  override fun onResult(result: User) {}
  override fun getUpdatableData(): Observable<User> {}
}

Now if i'm tring to create cached user repository instance, everything it's ok Then this code translates to application using dagger injections

val cachedUserRepo = CacheRepository<User, UserRepository>(UserRepository())

But! If i'm trying to result the list of data

class OrdersRepository: CacheEntity<List<Order>> {
  // overrides CacheEntity methods
}

val cachedOrdersRepo = CacheRepository<List<Order>, OrdersRepository>(OrdersRepository())

Everything is fine, but not in dagger-generated java code: MyComponent.java


private CacheRepository<List<Order>, OrdersRepository> cachedOrdersRepository;

error while building

error: type argument OrdersRepository is not within bounds of type-variable Entity
  private Provider<CachedRepository<List<Order>, OrdersRepository>> cachedOrdersRepository;
                                                              ^
  where Entity,Result are type-variables:
    Entity extends CacheEntity<Result> declared in class CacheRepository
    Result extends Object declared in class CacheRepository

Java code contains java.util.List which is incompatible with kotlin.collections.List, but dagger module class written in kotlin and returns valid kotlin kotlin.collections.List

@Module
object RepoModule {
  @JvmStatic
  @Provides
  fun provideCacheOrdersRepository(): CacheRepository<List<Order>, OrdersRepository> {
    return CacheRepository(OrdersRepository())
  }

}

So, how to solve this? I have a couple ideas, but i don't like this:

  • Rewrite dagger module in java, it worked before i converted to kotlin

  • Forced using java.util.List, but it's a very bad idea


Solution

  • This is related to the bytecode conversion of a Kotlin list and the wildcards added in the signature, making it a java.util.List<? extends T> instead of a java.lang.List<T>.

    To fix it without switching to an invariant type (e.g. MutableList) you should use @JvmSuppressWildcards on the the List type:

    e.g.

    class OrdersRepository: CacheEntity<List<@JvmSuppressWildcards Order>>
    

    I've added just one fragment of your full code, you should check your list usages and use @JvmSuppressWildcards on them.