3

I have the following APIs defined:

public interface Input<I> { Collection<? extends I> read(); } public interface Transformer<O, I> { Collection<? extends O> transform(Collection<? extends I> inputData); } public interface Output<O> { void write(Collection<? extends O> output); } public interface Executor { void execute(); } 

and the following implementations:

public final class InputImpl implements Input<String> { @Override public Collection<? extends String> read() { return asList("1", "2"); } } public final class TransformerImpl implements Transformer<Integer, String> { @Override public Collection<? extends Integer> transform(final Collection<? extends String> inputData) { return inputData.stream().map(Integer::parseInt).collect(Collectors.toList()); } } public final class OutputImpl implements Output<Integer> { @Override public void write(final Collection<? extends Integer> output) { System.out.println(output); } } public final class ExecutorImpl<I, O> implements Executor { private final Input<I> input; private final Transformer<O, I> transformer; private final Output<O> output; @Inject public ExecutorImpl(final Input<I> input, final Transformer<O, I> transformer, final Output<O> output) { this.input = input; this.transformer = transformer; this.output = output; } public void execute() { final Collection<? extends I> inputData = input.read(); final Collection<? extends O> outputData = transformer.transform(inputData); output.write(outputData); } } 

Here is my attempt to bind the APIs to the implementations from above:

public final class ModuleImpl extends AbstractModule { @Override protected void configure() { bind(new TypeLiteral<Input<String>>() { }).to(InputImpl.class); bind(new TypeLiteral<Transformer<Integer, String>>() { }).to(TransformerImpl.class); bind(new TypeLiteral<Output<Integer>>() { }).to(OutputImpl.class); bind(Executor.class).to(ExecutorImpl.class); } } 

When I am trying to get an instance of Executor using a Guice injector, I am getting the following errors:

1) com.csc.playground.guice.api.Input<I> cannot be used as a key; It is not fully specified. at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25) at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33) 2) com.csc.playground.guice.api.Transformer<O, I> cannot be used as a key; It is not fully specified. at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25) at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33) 3) com.csc.playground.guice.api.Output<O> cannot be used as a key; It is not fully specified. at com.csc.playground.guice.ExecutorImpl.<init>(ExecutorImpl.java:25) at com.csc.playground.guice.module.ModuleImpl.configure(ModuleImpl.java:33) 
1
  • I'm not sure it is possible. For example, what should injector.getInstance(Executor.class) inject into ExecutorImpl, if you have bound Output for several generic parameters? This is perfectly valid in Guice, because type literals will be different. Commented May 22, 2014 at 13:12

1 Answer 1

3

Conceptually, the problem is here:

@Inject public ExecutorImpl(final Input<I> input, final Transformer<O, I> transformer, final Output<O> output) { 

When guice attempts to fulfill the dependency for, say, Input<I>, it doesn't know what type it is; that's what "It is not fully specified" means.

You can fix this by specifying what the generic types are. You do this the same way you did the bindings in your AbstractModule, e.g instead of binding to ExecutorImpl.class, do:

bind(Executor.class).to(new TypeLiteral<ExecutorImpl<String, Integer>>() {}); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.