You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a Kotlin developer, I would like to use assisted inject with a functional type as a factory so that I am able to test my code with less boiler plate
So right now in Kotlin there is no elegant solution for binding kotlin.Function<A, B> as factories.
I thought I could circumvent this with guava's impossibly clever TypeLiteral, no dice.
Given the class
classComponent @Inject constructor(@Assisted importantRuntimeValue:Int){
interfaceFactory { funcreate(importantRuntimeValue:Int) : Component }
}
//...classComponentFactoryConsumer @Inject constructor(valfactory:Component.Factory){
//...
}
classComponentFactoryTestClass{
@Test funwhen_doing_X_should_result_in_Y(){
val componentUnderTest =ComponentFactoryConsumer( { importantRV -> mock(Component::class) } )
//not legal kotlin, since functional types exist in kotlin, SAM conversion is not available here.
}
}
The corresponding (almost identical) java has become idiomatic on our project
Since the above kotlin is not legal, as we move forward with kotlin, we need new idioms. Unfortunately the most obvious one requires some modifications within guice.
what I would like to do is skip the named factory type alltogether, and simply use a (Int) -> Component (kotlin alias for kotlin.Function<Int, Component> which itself is an alias for kotlin.jvm.functions.Function<Int, Component>), thus:
classComponent @Inject constructor(@Assisted importantRuntimeValue:Int){
//no need for named factory!
}
//...classComponentFactoryConsumer @Inject constructor(valfactory: (Int) ->Component){
//...
}
classComponentFactoryTestClass{
@Test funwhen_doing_X_should_result_in_Y(){
val componentUnderTest =ComponentFactoryConsumer( { importantRV -> mock(Component::class) } )
//now legal since the lambda is a simple function
}
}
May 06, 2016 4:20:08 PM com.google.inject.internal.MessageProcessor visit
INFO: An exception was caught and reported. Message: java.lang.IllegalArgumentException: Expected a Class, ParameterizedType, or GenericArrayType, but <? extends com.empowerops.language.KotlinLanguageFixture$KotlinClassWithJavaIdiomaticFactory> is of type com.google.inject.internal.MoreTypes$WildcardTypeImpl
java.lang.IllegalArgumentException: Expected a Class, ParameterizedType, or GenericArrayType, but <? extends com.empowerops.language.KotlinLanguageFixture$KotlinClassWithJavaIdiomaticFactory> is of type com.google.inject.internal.MoreTypes$WildcardTypeImpl
at com.google.inject.internal.MoreTypes.getRawType(MoreTypes.java:208)
at com.google.inject.TypeLiteral.<init>(TypeLiteral.java:90)
at com.google.inject.TypeLiteral.get(TypeLiteral.java:157)
at com.google.inject.TypeLiteral.resolve(TypeLiteral.java:181)
at com.google.inject.TypeLiteral.getReturnType(TypeLiteral.java:339)
at com.google.inject.assistedinject.FactoryProvider2.<init>(FactoryProvider2.java:239)
at com.google.inject.assistedinject.FactoryModuleBuilder$1.configure(FactoryModuleBuilder.java:334)
at com.google.inject.AbstractModule.configure(AbstractModule.java:62)
at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
at com.google.inject.AbstractModule.install(AbstractModule.java:122)
at com.empowerops.language.KotlinLanguageFixture$when_trying_to_use_reified_type_and_clever_typeLiteral_should_also_fail$1$1.configure(KotlinLanguageFixture.kt:74)
at com.google.inject.AbstractModule.configure(AbstractModule.java:62)
at com.google.inject.spi.Elements$RecordingBinder.install(Elements.java:340)
at com.google.inject.spi.Elements.getElements(Elements.java:110)
at com.google.inject.internal.InjectorShell$Builder.build(InjectorShell.java:138)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:104)
at com.google.inject.Guice.createInjector(Guice.java:96)
at com.google.inject.Guice.createInjector(Guice.java:73)
at com.google.inject.Guice.createInjector(Guice.java:62)
at com.empowerops.language.KotlinLanguageFixture$when_trying_to_use_reified_type_and_clever_typeLiteral_should_also_fail$1.call(KotlinLanguageFixture.kt:72)
at org.assertj.core.api.ThrowableAssert.catchThrowable(ThrowableAssert.java:61)
at org.assertj.core.api.StrictAssertions.catchThrowable(StrictAssertions.java:594)
at org.assertj.core.api.StrictAssertions.assertThatThrownBy(StrictAssertions.java:564)
at com.empowerops.language.KotlinLanguageFixture.when_trying_to_use_reified_type_and_clever_typeLiteral_should_also_fail(KotlinLanguageFixture.kt:72)
I'm not sure if the problem is the fact that I'm using the type-parametric factory (Int) -> Component (aka kotlin.Function<Int, Component>), or if the problem is within kotlin and its handling of contravariance, but in either event I figured guice should do something other than log a message at level info and then throw that same message as an exception.
The very similar code:
publicstaticclassComponent{
@InjectpublicComponent(@AssistedIntegervalue){}
}
@Testpublicvoidwhen_guice(){
TypeLiteral<Function<Integer, Component>> factoryInterfaceKey = newTypeLiteral<Function<Integer, Component>>() {};
AbstractThrowableAssertassertion = assertThatThrownBy(() -> {
Guice.createInjector(binder -> {
binder.install(newFactoryModuleBuilder().build(factoryInterfaceKey));
});
});
assertion.isInstanceOf(CreationException.class);
assertion.hasMessageContaining("Unable to create injector, see the following errors:");
assertion.hasMessageContaining("1) java.util.function.Function cannot be used as a key; It is not fully specified.");
}
}
... passes, meaning guice throws a more conventional exception when called from java.
tl;dr, add support for binding functional types as factories
The text was updated successfully, but these errors were encountered:
I really just want to use assisted inject from kotlin in any way possible. Right now the only thing I've got working is more no-fun anonymous object overloads.
So right now in Kotlin there is no elegant solution for binding
kotlin.Function<A, B>
as factories.I thought I could circumvent this with guava's impossibly clever
TypeLiteral
, no dice.Given the class
The corresponding (almost identical) java has become idiomatic on our project
Since the above kotlin is not legal, as we move forward with kotlin, we need new idioms. Unfortunately the most obvious one requires some modifications within guice.
what I would like to do is skip the named factory type alltogether, and simply use a
(Int) -> Component
(kotlin alias forkotlin.Function<Int, Component>
which itself is an alias forkotlin.jvm.functions.Function<Int, Component>
), thus:But this of course requires the binding code:
which results in
I'm not sure if the problem is the fact that I'm using the type-parametric factory
(Int) -> Component
(akakotlin.Function<Int, Component>
), or if the problem is within kotlin and its handling of contravariance, but in either event I figured guice should do something other than log a message at level info and then throw that same message as an exception.The very similar code:
... passes, meaning guice throws a more conventional exception when called from java.
tl;dr, add support for binding functional types as factories
The text was updated successfully, but these errors were encountered: