1
votes

I'm new to Guice, so excuse me if this is a dumb question, but I'm finding it quite frustrating.

In my module I construct an object which is a member of a framework that I do not control. I then bind that instance so that I can access it later with injector.getInstance(FrameworkClass.class);

When I construct that object, I want to use one of my own objects which itself is annotated to be injected by constructor.

i.e.

public class MyClass { 
    OtherClass dependency;

    @Inject
    Public MyClass(OtherClass dependency) {
       ....
    }
}

public class AModule extends AbstractModule {

    protected void configure() {
        MyClass frameworkDependency = ???
        FrameworkClass fc = new FrameworkClass(frameworkDependency);
        bind(FrameworkClass.class).toInstance(fc);
    }
}

In this example OtherClass is just a simple class with no annotations but a default empty constructor, so Guice should just new one up and provide it to MyClass constructor as far as I understand.

My question is How do I get access to a new instance of MyClass in my module so that I can provide it to the framework class?

Previously I had my own class injected via Field Injection, so it looked like this:

public class MyClass { 

    @Inject
    OtherClass dependency;      
}

public class AModule extends AbstractModule {

    protected void configure() {
        MyClass frameworkDependency = new MyClass();
        requestInjection(frameworkDependency);
        FrameworkClass fc = new FrameworkClass(frameworkDependency);
        bind(FrameworkClass.class).toInstance(fc);
    }
}

I would prefer to keep MyClass as constructor injected if possible.

2

2 Answers

2
votes

If you use a @Provides method, as in your answer, every parameter will be resolved through the injector--including dependencies that use binding annotations, and including parameters of type Provider<MyClass> instead of just MyClass. Injecting Providers is the best way to retrieve multiple instances of a dependency in one class.

@Provides FrameworkClass provideFrameworkClass(
    Dependency1 dep1, Provider<Dependency2> dep2Provider) {
  return new FrameworkClass(dep1, dep2Provider.get(), dep2Provider.get());
}

If all of your bindings can be found through Guice, you can more-or-less externally mark a constructor with @Inject by using a toConstructor binding. Note that the Guice docs actually prefer the @Provides technique over this technique, since getting Constructors reflectively is inherently more fragile than relying on your compiler. It may be a good option if you have a long parameter list, though.

Finally, if your @Provides method is big enough (or has complex-enough logic) to merit its own class, you can always create your own implementation of Provider<FrameworkClass>--complete with as much @Injection as you'd like--and implement the creation manually (bound through bind(FrameworkClass.class).toProvider(FrameworkClassProvider.class).

0
votes

So I found the answer my own question (in its simplest form):

By moving the configuration of the Framework Object into a Provides method I can pass the MyClass object in as a parameter to the method and Guice handles in the instantiation of that parameter, ala:

@Provides
@Singleton
FrameworkClass provideFrameworkClass(MyClass dependency) {
    return new FrameworkClass(frameworkDependency);
}

But that begs the question what happens in the more complex case, what if my framework didn't take a single dependency, but n of them (say it's a dispatcher taking a bunch of actions), I can't just extend my provideFrameworkClass method to take n+ parameters?