Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No implementation was bound - Java Guice

Tags:

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?

like image 257
Lorena Nicole Avatar asked Jul 15 '14 19:07

Lorena Nicole


2 Answers

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.

like image 190
Miguel Avatar answered Sep 20 '22 05:09

Miguel


Not the source of the issue in this particular case, but I ran across this issue when I had my implementation and interface classes backwards:

public class MyModule extends AbstractModule {
    @Override
    public void configure() {
        bind(MyClassImpl.class).to(MyInterface.class);
    }
}

Should have been:

bind(MyInterface.class).to(MyClassImpl.class);
like image 9
Nate Vaughan Avatar answered Sep 23 '22 05:09

Nate Vaughan