Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice Inject Field in class not created by Guice

I have a class like so, that I create myself somewhere in my code:

class StarryEyes {
   @Inject MyValidator validator;

   public StarryEyes(String name) {
      //..
   }

   public doSomething() {
      // validator is NULL
   }
}

I want Guice to inject an instance of validator, which has a @Singleton annotation. I have a module that's loaded at startup and it contains the line:

bind(MyValidator.class);

However, it doesn't seem to work as "validator" is always null. I've tried a number of variations like:

bind(MyValidator.class)toInstance(new MyValidator());

or other things like that. Is this not how Guice is supposed to work?

like image 214
Verhogen Avatar asked Aug 04 '10 11:08

Verhogen


People also ask

How does @inject work Guice?

Using GuiceIn each of your constructors that need to have something injected in them, you just add an @Inject annotation and that tells Guice to do it's thing. Guice figures out how to give you an Emailer based on the type. If it's a simple object, it'll instantiate it and pass it in.

Can Guice inject null?

Guice forbids null by default So if something tries to supply null for an object, Guice will refuse to inject it and throw a NULL_INJECTED_INTO_NON_NULLABLE ProvisionException error instead. If null is permissible by your class, you can annotate the field or parameter with @Nullable .

What is dependency injection Guice?

Guice is an open source, Java-based dependency injection framework. It is quiet lightweight and is actively developed/managed by Google. This tutorial covers most of the topics required for a basic understanding of Google Guice and to get a feel of how it works.


1 Answers

Typically Guice needs to create objects to inject them. If you just call new StarryEyes(name), Guice isn't ever going to see that object so it won't be able to inject it. One thing you can do is to call injector.injectMembers(obj) on the object after you've created it. I wouldn't recommend that, though, as you should avoid referencing the injector in your code.

What you really probably want here is Assisted Inject. With Assisted Inject, you'd declare the constructor for your class something like this:

@Inject public StarryEyes(MyValidator validator, @Assisted String name)

What that means is that validator is a parameter that Guice should inject, while name must be "assisted" (that is, provided at the time the instance is created).

You then create an interface like this:

public interface StarryEyesFactory {
  StarryEyes create(String name);
}

With Assisted Inject, Guice can then implement that factory for you. You bind it like this:

bind(StarryEyesFactory.class).toProvider(
    FactoryProvider.newFactory(StarryEyesFactory.class, StarryEyes.class));

You then inject a StarryEyesFactory anywhere you want to create an instance of it. Where you would have called new StarryEyes(name) previously, you now call starryEyesFactory.create(name) instead. When you call create(name) on the factory, it will take the name and pass it to the constructor and provide the bound validator itself.

Starting in Guice 3, you do this using a FactoryModuleBuilder:

install(new FactoryModuleBuilder().build(StarryEyesFactory.class));
like image 53
ColinD Avatar answered Oct 21 '22 18:10

ColinD