Guice configuration error: No implementation was bound
There are several problems I'm seeing here.
First, Callable
and Callable<String>
are different. If you want to inject a Callable<String>
(or Processor<String, String>
, etc.) in Guice, you have to bind something to Callable<String>
, not Callable
.
Second, you're binding Callable
to JMeterTask
which implements Callable<JMeterRawResults>
but you're injecting Callable<String>
in JMeterComponent
's constructor (same deal for Processor
and Renderer
). I'm going to assume that JMeterComponent
should have Callable<JMeterRawResults>
etc. injected.
Anyway, what you need to do is generic bindings using TypeLiteral
:
bind(new TypeLiteral<Callable<JMeterRawResults>>(){})
.annotatedWith(Names.named("JMeter"))
.to(JMeterTask.class);
Related videos on Youtube
Roman
Updated on July 09, 2022Comments
-
Roman over 1 year
I'm trying to make DI with Guice work, doing (as it seems to me) exactly what's in the manual.
I can't explain the problem because I don't really understand it - everything seems very logical and should work.. but it doesn't. So, I can only attach the code and the stacktrace:
public class Runner { public static void main(String[] args) { Injector injector = Guice.createInjector(new TestModule()); //next line throws the exception JMeterComponent jMeterComponent = injector.getInstance(JMeterComponent.class); .... } }
As you can see, I'm trying to instantiate object of
JMeterComponent
class. It's constructor (as you'll see later) accepts 3 arguments: all of them should be also instantiated by IoC and injected.And here's the
TestModule
with configuration of these 3 arguments:public class TestModule extends AbstractModule { @Override protected void configure() { bind(Callable.class).annotatedWith(Names.named("JMeter")) .to(JMeterTask.class); bind(Processor.class).annotatedWith(Names.named("JMeter")) .to(JMeterResultsProcessor.class); bind(Renderer.class).annotatedWith(Names.named("JMeter")) .to(JMeterResultsWikiRenderer.class); } }
Now, let's look at those concrete implementations -
JMeterTask
,JMeterResultsProcessor
andJMeterResultsWikiRenderer
(all of them have fake bodies for the simplicity):public class JMeterTask implements Callable<JMeterRawResults> { public JMeterRawResults call() throws Exception { return new JMeterRawResults(); } }
public class JMeterResultsProcessor implements Processor<JMeterRawResults, JMeterResults> { public JMeterResults process(JMeterRawResults raw) { return new JMeterResults(); } }
public class JMeterResultsWikiRenderer implements Renderer<JMeterResults> { public Map<String, String> render(JMeterResults jMeterResults) { Map<String, String> results = Maps.newHashMap(); ... return results; } }
And now let's look at the
JMeterComponent
class, which instance's construction is the aim of the whole DI-related stuff here:public class JMeterComponent extends AbstractComponent<String, String> { @Inject public JMeterComponent(@Named("JMeter") Callable<String> task, @Named("JMeter")Processor<String, String> processor, @Named("JMeter")Renderer<String> renderer) { super(task, processor, renderer); } }
And here's the stacktrace:
Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors: 1) No implementation for stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound. while locating stat.domain.Processor<java.lang.String, java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) for parameter 1 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18) while locating cstat.components.jmeter.JMeterComponent 2) No implementation for stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound. while locating stat.domain.Renderer<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) for parameter 2 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18) while locating stat.components.jmeter.JMeterComponent 3) No implementation for java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) was bound. while locating java.util.concurrent.Callable<java.lang.String> annotated with @com.google.inject.name.Named(value=JMeter) for parameter 0 at stat.components.jmeter.JMeterComponent.<init>(JMeterComponent.java:18) while locating stat.components.jmeter.JMeterComponent
Some additional facts:
- I use guice-2.0 (with
featured
label) - There's no more any annotation from
com.google.inject
package in any other class in the code - Interfaces
Processor
andRenderer
are placed in one module, and theirjmeter
-implementations (JMeterResultsProcessor
and other) andJMeterComponent
class are placed in another module.
That's pretty much everything there's to say about it.
Sorry for such a long post and thanks for your patience to read it to the end.
Any ideas on why did the errors occur and how to fix it?
- I use guice-2.0 (with
-
Roman almost 13 yearsYes, this works. Unfortunately, it looks not pretty well. Anyway, thanks very much.
-
whiskeysierra almost 13 yearsAgreed that this looks ugly. I usually define the literals in instance variables in the modules, because they are somehow static. This makes the bind statement a lot nicer.
-
ColinD almost 13 yearsI don't really see the big deal. Once you get used to the
TypeLiteral
idiom in Guice, it looks perfectly natural there. I say don't fight the idiomatic way of doing things in Guice... but whatever you prefer. -
cytinus over 9 yearsWhen you use Guice, the module is where the ugly code is supposed to go, so you don't need ugly code in your business logic.