2016-04-14 81 views
5

我写在科特林与以下控制器定义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() 

} 

和multibinding扩展(切换列表设置在科西嘉的字段定义):

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 gerenic方差和Guice严格类型检查有关。但我不知道如何宣布这个绑定,所以Guice会知道该怎么注入这个领域。

回答

13

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

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

默认情况下科特林生成用于componentDescriptorsList<? extends ComponentDescriptor>签名。 @JvmSuppressWildcards使其生成一个简单的参数化签名List<ComponentDescriptor>

3

@Michael给出了正确的answer和解释。下面是一个单元测试Set多重绑定的示例,用于那些喜欢测试其模块的人:

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) 
    } 
}