Guice configuration error: No implementation was bound

48,108

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);
Share:
48,108

Related videos on Youtube

Roman
Author by

Roman

Updated on July 09, 2022

Comments

  • Roman
    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 and JMeterResultsWikiRenderer (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:

    1. I use guice-2.0 (with featured label)
    2. There's no more any annotation from com.google.inject package in any other class in the code
    3. Interfaces Processor and Renderer are placed in one module, and their jmeter-implementations (JMeterResultsProcessor and other) and JMeterComponent 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?

  • Roman
    Roman almost 13 years
    Yes, this works. Unfortunately, it looks not pretty well. Anyway, thanks very much.
  • whiskeysierra
    whiskeysierra almost 13 years
    Agreed 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
    ColinD almost 13 years
    I 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
    cytinus over 9 years
    When 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.