I am trying to migrate a small project, replacing some factories with Guice (it is my first Guice trial). However, I am stuck when trying to inject generics. I managed to extract a small toy example with two classes and a module:
import com.google.inject.Inject; public class Console<T> { private final StringOutput<T> out; @Inject public Console(StringOutput<T> out) { this.out = out; } public void print(T t) { System.out.println(out.converter(t)); } } public class StringOutput<T> { public String converter(T t) { return t.toString(); } } import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.TypeLiteral; public class MyModule extends AbstractModule { @Override protected void configure() { bind(StringOutput.class); bind(Console.class); } public static void main(String[] args) { Injector injector = Guice.createInjector( new MyModule() ); StringOutput<Integer> out = injector.getInstance(StringOutput.class); System.out.println( out.converter(12) ); Console<Double> cons = injector.getInstance(Console.class); cons.print(123.0); } }
When I run this example, all I got is:
Exception in thread "main" com.google.inject.CreationException: Guice creation errors:
1) playground.StringOutput<T> cannot be used as a key; It is not fully specified. at playground.MyModule.configure(MyModule.java:15) 1 error at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354) at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152) at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105) at com.google.inject.Guice.createInjector(Guice.java:92)
I tried looking for the error message, but without finding any useful hints. Further on the Guice FAQ I stumble upon a question about how to inject generics. I tried to add the following binding in the configure
method:
bind(new TypeLiteral<StringOutput<Double>>() {}).toInstance(new StringOutput<Double>());
But without success (same error message).
Can someone explain me the error message and provide me some tips ? Thanks.
I think the specific issue you're seeing is probably because of the bind(Console.class)
statement. It should use a TypeLiteral
as well. Or, you could just bind neither of those and JIT bindings will take care of it for you since both of the types involved here are concrete classes.
Additionally, you should retrieve the Console
with:
Console<Double> cons = injector.getInstance(Key.get(new TypeLiteral<Console<Double>>(){}));
Edit: You don't need to bind to an instance just because you're using a TypeLiteral
. You can just do:
bind(new TypeLiteral<Console<Double>>(){});
Of course, like I said above you could just skip that in this case and retrieve the Console
from the injector using a Key
based on the TypeLiteral
and the binding would be implicit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With