1

Taking a look at Guice (and Dagger) for a new project. Every Guice tutorial I have seen so far shows an injector being created at the point where the developer needs the DI to create an object instance.

A typical example seen on the web:

public static void main(String[] args) {
    Injector injector = Guice.createInjector(new BasicModule());
    Communication comms = injector.getInstance(Communication.class);
}

To me this defeats the purpose of the DI - everywhere an instance is required, you tie the instance to the modules which define how to build it.

Is there a way to ask Guice to create an instance of a class who's module (dependency graph) has been previously defined to Guice (eg. at application startup?).

I am using the Dropwizard.io framework so there are situations where I don't have full control over the way a class is constructed but want to be able to mock out the dependencies I reference in that class.

Exactly the same applies to Dagger - I'd appreciate examples for either/both.

Edit: I've worked with several DI frameworks in .NET over the years, so I'm going to give an example of what I'm trying to do based on one of those.

For example, in the ASP.NET Core DI implementation, at service start-up you define the services you want the DI to be able to create. Typically you'll be asking the DI to give you an instance which is an implementation of an interface. So at start-up:

protected override void ConfigureAdditionalServices(IServiceCollection services)
{
    services.AddScoped<ITransactionService, TransactionService>();
}

where IServiceCollection is the collection of services defined to the DI.

Because the DI is integrated with the ASP.NET framework, from this point on you can generally define a constructor which takes ITransactionService and the DI will provide it for you.

However, if you were using the DI in a framework which did not know about it, you'd need access to the current ServiceProvider instance, and then you could ask the DI to create your object like this:

var transactionService = ServiceProvider.GetService<ITransactionService>();

I realise that this implemeting the Service Locator anti-pattern but it still has the benefit of decoupling my code from the concrete class implementations and allowing me to mock them out for testing at application start-up.

So back to the question So to restate my question in the light of this context, how can I request a class from Guice at some random point in my code?

What would I need to change in this code to make it work?

public class TransactionModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionServiceBase.class).to(TransactionService.class);
  }
}

// At startup
Injector injector = Guice.createInjector(new TransactionModule());


// Then, somewhere in the application, to get an instance of TransactionService
TransactionServiceBase transactionService = (TransactionServiceBase)Guice.getInstance(TransactionServiceBase.class);

Peter
  • 5,455
  • 7
  • 46
  • 68

2 Answers2

0

I think you might be misunderstanding Injector.getInstance - in the same way that your example has a public static method to start things off, even though you don't usually write the rest of your app with all public static methods (I hope), you also don't call Injector.getInstance except in a very few specific cases.

Instead, this code is just used to get things going. Another popular "get this started" is injector.injectMembers(this) - let the main() create an instance manually of whatever is the basis of your application, with @Inject-annotated members, and then just ask the now-created Injector to populate the members.

As you continue "inward" to the rest of your application, you likely will never reference the Injector instance again, but instead rely on providers, assisted inject, or just guice-created instances.

In this way, you should never care about the Injector or the exact modules that were set up for it. Only one Injector should exist over the lifetime of the app (there are essentially no exceptions to this, except perhaps if you redefine what an "app" is), and 99% of the time it is hidden from you (exceptions: where your DI meets some other DI, and needs to request an instance of something by its Class, or where you have tooling that wants to introspect the set of all declared bindings). As such, you should be able to just provide setters, constructor args, or init methods, and then can call them manually, or have any guice context create them based on their own specific modules and rules.

Colin Alworth
  • 17,801
  • 2
  • 26
  • 39
  • Thanks Colin, sounds like what I am trying to do. Are you able to provide or point me to an example? – Peter Jan 10 '20 at 17:45
  • I'm not sure what that example would show exactly - can you put a little more code in your question, demonstrating what you are trying to do more specifically, so I can tailor it better? – Colin Alworth Jan 10 '20 at 21:08
  • I'm looking for 1) a piece of code which defines an object/module to Guice at application start and 2) a line or two of code which would reside somewhere else in the application which shows how to request an instance of the object from Guice. eg. does Guice have a static provider which you can use to say, perhaps, `MyClass myClass = Guice.createInstance("MyClass.class")`? – Peter Jan 11 '20 at 07:57
  • If you literally need "give me an instance of something, but I don't know at compile time what it is (or is bound as), so here is a `java.lang.Class` which represents it", that is one answer. On the other hand, if you actually know the `MyClass` (as used on left and right of your sample code) then yes, this is very doable. Can you clarify, and I'll add it? – Colin Alworth Jan 11 '20 at 19:08
  • Hi Colin - I've extended the question to give context of the situation and what I'm trying to achieve, I'm hoping that helps. – Peter Jan 13 '20 at 09:27
0

I think that the answer is that there is no standard/supported way to do that.

The usual assumptions is that you have as few 'injections' points as possible, ideally one, and then you specify what each class needs by making dependencies constructor arguments.

The only scenario I know well similar to what you describe here is Dagger in android apps. The way they solved it is that they store the dagger "Injector" (sorta) in a global object - the Application, and then Dagger provides a static function to retrieve that object and perform the injections.

Long story short DI frameworks don't play well with paradigms where you don't instantiate classes yourself.

And the only solution I can think of is storing your injector in some global variable and get it from there when you need it.

Static injection might help to some degree in your case https://github.com/google/guice/wiki/Injections#static-injections

al3c
  • 1,392
  • 8
  • 15