Search code examples
javadependency-injectionannotationsguice

No implementation was bound - Java Guice


Novice here trying to use a dummy Java Facebook app that uses Guice to inject a database dependency into the Facebook factory but continue to have Guice error out telling me:

### No implementation for com.example.storage.Db annotated with @com.example.storage.annotations.SystemDb() was bound while locating com.example.storage.Db annotated with @com.example.storage.annotations.SystemDb() for parameter 0 at com.example.facebook.client.exceptions.FacebookExceptionHandlerDb at com.example.facebook.client.guice.FacebookClientModule.configure

### Could not find a suitable constructor in com.example.facebook.statsd.StatsdClient. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private. at com.example.facebook.statsd.StatsdClient.class while locating com.example.facebook.statsd.StatsdClient for parameter 1 at com.example.facebook.client.exceptions.FacebookExceptionHandlerDb. com.example.facebook.client.guice.FacebookClientModule.configure

Code for app:

app.java

package com.example.facebook;

import com.google.inject.Guice;
import com.restfb.Connection;
import com.restfb.types.Post;
import com.example.facebook.client.FacebookClientFactory;
import com.example.facebook.client.RobustFacebookClient;
import com.example.facebook.client.guice.FacebookClientModule;
import com.example.facebook.statsd.StatsdClient;

public class App  {
    public static void main ( String[] args ) {
          final FacebookClientFactory facebookClientFactory =
            Guice.createInjector(new FacebookClientModule()).getInstance(FacebookClientFactory.class);
          //error from line above
          final RobustFacebookClient robustFacebookClient =
            facebookClientFactory.create("accessToken");
          //more ...
    }

The resulting error points me to the FacebookClientModule binding:

FacebookClientModule.java

public class FacebookClientModule extends AbstractModule {
    bind(FacebookExceptionHandler.class).to(FacebookExceptionHandlerDb.class);
    //error resulting from the failed binding on the FacebookExceptionHandlerDB class

    install(new FactoryModuleBuilder()
            .implement(FacebookClient.class, RobustFacebookClient.class)
            .build(FacebookClientFactory.class));
    }

}

Where inside the FacebookExceptionHandleDB class the constructor has the injection:

FacebookExceptionHandlerDB.java

public class FacebookExceptionHandlerDb implements FacebookExceptionHandler {

    // list of class String variables ... 
    private final FacebookErrorParser parser;
    private final Db db;
    private StatsdClient statsd;

    @Inject
    public FacebookExceptionHandlerDb(@SystemDb Db db, StatsdClient statsd,    FacebookErrorParser parser) {
        this.db = db;
        this.statsd = statsd;
        this.parser = parser;
    }
}

From what I can gleam, the dependency injection for parameters zero and one, db and statsD respectively, is failing. Could someone point out where or what in the app code is missing?


Solution

  • At first glance it seems like your missing the bindings for the Db annotated dependency and the StatsdClient.

    You'll need to provide the missing bindings to your module like so

    bind(Db.class).annotatedWith(SystemDb.class).to(DbImplOfSomeSort.class);
    bind(StatsdClient.class).to(StatsdClientImplOfSomeSort.class);
    

    Guice is able to automatically inject Concrete Class with either a public no argument constructor or a constructor with @Inject without any specific defined binding in your module but when it comes to Interfaces you have to define the necessary bindings.

    Here Db.class and StatsdClient.class are interfaces which you need to bind to specific implementation.