Link a list of objects using Guice + Kotlin

I am writing a JavaFX application in Kotlin with the following controller definition:

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

I am using Guice for Dependency management. And I'm trying to enter a list of class instances loaded through java.util.ServiceLoader . My problem is defining a binding that will enter a list of loaded object objects into the declared field. I tried annotation based creation:

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

and multiply-connected extension (switch list for installation in the cors definition field):

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

but both of these approaches lead to the same error:

 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 

I'm starting to suspect that this has something to do with the variation of Gotenic Kotlin and a thorough check like Guice. But I don’t know how to declare a binding, so Geis will know what needs to be entered in this field.

+7
dependency-injection guice kotlin
source share
3 answers

Yes, this is due to variance, but there is a way to make it work.

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

By default, Kotlin generates a List<? extends ComponentDescriptor> List<? extends ComponentDescriptor> for the componentDescriptors field. @JvmSuppressWildcards allows @JvmSuppressWildcards to generate a simple parameterized signature List<ComponentDescriptor> .

+16
source share

@Michael gives the correct answer and explanation. Here is an example of one strategy for unit testing a Set multibinding for those who like to test their modules:

 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) } } 
+3
source share

@Michael comment works. If you want to make an injection into the constructor, you need to do something like

 class MainController @Inject consturctor( private var componentDescriptors: List<@JvmSuppressWildcards ComponentDescriptor> ) {} 
0
source share