Guice: Building Related Trees of Objects / Robot Legs

794 views Asked by At

I have a class A that holds a class B like this:

class A {
   private final B b;
   @Inject
   A(B b) {
     this.b = b;
   }
}

interface B {}
class B1 implements B {}
class B2 implements B {}

class Client() {
   @Inject 
   Client(@AhasB1 A aHasB1, @AhasB2 A aHasB2) { }
}

I'd like to bind two different A's, one annotated @AhasB1 and another @AhasB2. How can I bind these correctly?

3

There are 3 answers

0
Jeff Axelrod On BEST ANSWER

Here's how I did it using PrivateModule.

public class MainModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new PrivateModule(){
            @Override
            protected void configure() {
                bind(A.class).annotatedWith(AhasB1.class).to(A.class);
                expose(A.class).annotatedWith(AhasB1.class);
                bind(B.class).to(B1.class);
            }
        });

        install(new PrivateModule(){
            @Override
            protected void configure() {
                bind(A.class).annotatedWith(AhasB2.class).to(A.class);
                expose(A.class).annotatedWith(AhasB2.class);
                bind(B.class).to(B2.class);
            }
        });
}
0
Colin Alworth On

Instead of using @Provides methods, consider a set of Provider<A> types, possibly nested in the type A, granting you access to the private ctor. Or make it a package-protected ctor, and put the providers in the same package as it. Or, of course, you could move your Module type into the same package as A.

Another option would be AssistedInject, which would allow you to specify a set of methods that would, based on name or param, would return different instances (in your case, probably subtypes of A). I think it will have access to private constructors.

One last thought for you: Why not leave the constructor to A as public, so that a user of the library can manually inject dependencies? If this is for internal use only, documenting the ctor could also suffice.

0
Darren Gilroy On

I think the solution you are looking for is Private Modules

  1. You will need two instances of PrivateModule, one each for B1 and B2
  2. Bind B to the appropriate concrete type
  3. expose(A.class).annotatedWith(B1.class)

http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/PrivateModule.html

-dg