使用Guice + Kotlin绑定对象列表

我正在使用以下控制器定义在Kotlin中编写JavaFX应用程序:

class MainController { @Inject private lateinit var componentDescriptors: List<ComponentDescriptor> /* More code goes here */ } 

我正在使用Guice进行依赖管理。 我试图注入通过java.util.ServiceLoader加载的类实例的列表。 我的问题是定义一个绑定,将注入加载的对象实例列表到声明的字段。 我尝试基于注释的供应:

 internal class MyModule: AbstractModule() { override fun configure() { } @Provides @Singleton fun bindComponentDescriptors(): List<ComponentDescriptor> = ServiceLoader.load(ComponentDescriptor::class.java).toList() } 

和多重绑定扩展(在Corse的字段定义中切换列表设置):

 internal class MyModule: AbstractModule() { override fun configure() { val componentDescriptorBinder = Multibinder.newSetBinder(binder(), ComponentDescriptor::class.java) ServiceLoader.load(ComponentDescriptor::class.java).forEach { componentDescriptorBinder.addBinding().toInstance(it) } } } 

但是这两种方法都会导致相同的错误:

 No implementation for java.util.List<? extends simpleApp.ComponentDescriptor> was bound. while locating java.util.List<? extends simpleApp.ComponentDescriptor> for field at simpleApp.MainController.componentDescryptors(MainController.kt:6) while locating simpleApp.MainController 1 error at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1042) at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1001) at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051) at com.gluonhq.ignite.guice.GuiceContext.getInstance(GuiceContext.java:46) at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:929) at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971) at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220) at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744) at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707) at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527) ... 12 more 

我开始怀疑它与Kotlin的显着差异和Guice严格类型检查有关。 但是我不知道如何宣布这个绑定,所以Guice会知道该怎么注入这个领域。

是的,这是因为差异而发生的,但有一种方法可以使其工作。

 class MainController { @JvmSuppressWildcards @Inject private lateinit var componentDescriptors: List<ComponentDescriptor> } 

默认情况下,Kotlin生成List<? extends ComponentDescriptor> List<? extends ComponentDescriptor> componentDescriptors字段的List<? extends ComponentDescriptor>签名。 @JvmSuppressWildcards使它生成一个简单的参数化签名List<ComponentDescriptor>

@迈克尔给出了正确的答案和解释。 下面是一个为那些喜欢测试模块的单元测试Set multiplebinding的策略的例子:

 class MyModuleTest { @JvmSuppressWildcards @Inject private lateinit var myTypes: Set<MyType> @Before fun before() { val injector = Guice.createInjector(MyModule()) injector.injectMembers(this) } @Test fun multibindings() { assertNotNull(myTypes) assertTrue(myTypes.iterator().next() is MyType) } }