19

I have been trying to get Guice working but end up with this:

Classes must have either one (and only one) constructor

My interface:

public interface AddrBookStore {
    public Contact getContactByKey(String key);
    public void addContact(Contact c);
}

The implementation:

public class RdbmsBasedAddrBookStore implements AddrBookStore {
    private Connection connection;

    public RdbmsBasedAddrBookStore(Connection connection) {
        this.connection = connection;
    }

    @Override
    public Contact getContactByKey(String key) throws AddrBookException
    {} 
    @Override
    public void addContact(Contact c) throws AddrBookException
    {}
}

The binding module:

public class ABguiceConfingModule extends AbstractModule {
    @Override
    protected void configure() {        
        bind(AddrBookStore.class).to(RdbmsBasedAddrBookStore.class);
    }
}

The AddrBook client where I am injecting:

public class AddrBook {
    private AddrBookStore store;

    @Inject
    public AddrBook(AddrBookStore store)
    {
        this.store = store;
    }
    ... other methods;
}

And my main:

public class App 
{
    public static void main( String[] args ) throws Exception
    {
        Injector injector = Guice.createInjector(new ABguiceConfingModule() );
        AddrBookStore store = injector.getInstance( AddrBookStore.class );

        AddrBook book = new AddrBook(store);
        AddrBookCLI cli = new AddrBookCLI(book);
        cli.interact(new InputStreamReader(System.in), new OutputStreamWriter(System.out));

}}

After all this, I'm getting this error:

1) Could not find a suitable constructor in addrbook.store.RdbmsBasedAddrBookStore. Classes must have either one (and only one) constructor annotated with @Inject or a zero-argument constructor that is not private.
[ERROR] at addrbook.store.RdbmsBasedAddrBookStore.class(RdbmsBasedAddrBookStore.java:23)
[ERROR] at addrbook.ABguiceConfingModule.configure(ABguiceConfingModule.java:13)

I have experience with Spring and not with Guice. Where am I going wrong here?

durron597
  • 31,968
  • 17
  • 99
  • 158
Kartz Kartel
  • 193
  • 1
  • 1
  • 4
  • The error message says you must have either a constructor annotated with @Inject, or it must have a non-private zero-argument constructor. The code you show for the ABguiceConfingModule class does not have any such constructor. – FredK Jun 28 '16 at 18:39
  • I imagine Fred means RdbmsBasedAddrBookStore has no such constructor, which I agree with. Modules like ABguiceConfingModule can have any constructor you want, because you're calling it yourself to feed into createInjector. You'll probably want to add an @Inject annotation to RdbmsBasedAddrBookStore and make sure Connection is bound in one of your modules. – Jeff Bowman Jun 28 '16 at 21:21

2 Answers2

9

You haven't set up the primary dependency for AddrBookStore. You need to have a binding for Connection, and then you need to annotate the constructor with @Inject.

You've set up the AddrBookStore class but clearly it's wrapping an Rdbms... except you haven't set up the Rdbms.

There are lots of ways to do this in Guice, in this case I would probably do it with a Provider<Connection>, that way you have an entire class to put the code for spinning up your connection to the database, so something like:

public class ConnectionProvider implements Provider<Connection> {
    public Connection get() {
        // put your code that connects to the database here
    }
}

Then your module would be:

public class ABguiceConfingModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(AddrBookStore.class).to(RdbmsBasedAddrBookStore.class);
        bind(Connection.class).toProvider(ConnectionProvider.class);
    }
}

And then finally your AddrBookStore:

public class RdbmsBasedAddrBookStore implements AddrBookStore {
    private Connection connection;

    @Inject
    public RdbmsBasedAddrBookStore(Connection connection) {
        this.connection = connection;
    }

    @Override
    public Contact getContactByKey(String key) throws AddrBookException
    {}

    @Override
    public void addContact(Contact c) throws AddrBookException
    {}
}
durron597
  • 31,968
  • 17
  • 99
  • 158
  • Thanks that solution worked. The only problem i find is if tommorow, i may want to change the impltementation to say file base storage or into some nosql db, like `bind(AddrBookStore.class).to(FileBasedAddrBookStore.class);` I will have to create another binding similar to what you have mentioned in the configmodule `bind(File.class).toProvider(FileProvider.class);` – Kartz Kartel Jul 03 '16 at 08:31
  • @KartzKartel that's correct, in Guice if you want to change the binding you have to make a code change (to the module), it's not just a config XML file like Spring. However you could argue Guice is more powerful because you get the full language to spin up your dependencies. – durron597 Jul 03 '16 at 08:46
0

Had this error message because I forget to add annotation @Inject on constructor. public AddrBook(AddrBookStore store) in the case of this question.

z atef
  • 7,138
  • 3
  • 55
  • 50