匕首2不识别Kotlin的提供方法。 Java工作正常

匕首不认可Kotlin提供的一种方法。 这是模块的重要部分:

@Provides @AppScope fun provideClient(cache: Cache, interceptors: List<Interceptor>?): OkHttpClient { val httpBuilder = OkHttpClient.Builder() interceptors?.let { for (interceptor in interceptors) { httpBuilder.addInterceptor(interceptor) } } return httpBuilder .cache(cache) .build() } @Provides @AppScope fun provideInterceptors(): List<Interceptor>? { return listOf(HttpLoggingInterceptor().setLevel(WebServiceConfig.LOGGING_LEVEL)) } 

错误消息如下所示:

 AppComponent.java:15: error: java.util.List<? extends okhttp3.Interceptor> cannot be provided without an @Provides-annotated method. 

如果我使用MutableList,那么它工作。 所以问题是:Dagger2 / Kotlin中的列表有什么问题?

原来这是一个泛型互操作问题。

当你在Kotlin中使用一个接口的List (如Interceptor )作为参数时,你会发现它具有Java的角度来看列表的类型参数的通配符,因为List是协变的:

 OkHttpClient provideClient(List<? extends Interceptor> interceptors) { ... } 

但是,通配符不会被添加到返回类型中。

 List<Interceptor> provideInterceptors() { ... } 

您可以通过在Java文件中创建模块的实例并查看自动完成提供的方法来检查。

所以问题是Dagger正在寻找一个List<? extends Interceptor> List<? extends Interceptor>而你的另一个方法返回一个List<Interceptor>

可能的解决方案:

  1. 使用@JvmSuppressWildCards批注来防止添加通配符(请参阅此处的相关问题)。 这可以在任何范围内使用,从整个模块一直到只有单个类型参数都有问题:

     interceptors: List<@JvmSuppressWildcards Interceptor>? 
  2. 在你正在返回的List中添加明确的差异在provideInterceptors方法。 有趣的是,当你从Java中看到自动完成时,这并不显示,但它修复了构建。

     fun provideInterceptors(): List<out Interceptor>? { ... } 
  3. 使用MutableList接口,正如你所发现的,没有这个问题。


至于为什么只有当你使用List而不是MutableList时才会发生这种情况: List只有在out位置的类型参数,因此它是协变的。 这将导致通配符为List生成,但不为不变的MutableList (这就是为什么工作正常)。

还要注意,这个通配符的生成只在类型参数是一个非最终类型(一个公开类或一个接口)时才会发生。 所以你不会得到这个问题,例如一个List<StringBuilder> (这是最后一个),但你会得到一个List<BufferedReader> (不是)。