NSF
NSF

Reputation: 2549

Can I get the instance in a method using Guice?

I just started using Guice so my understanding could be completely wrong.

I have an interface Foo and an implmentation FooImp

I have used the following code in my module to inject it:

bind(Foo.class).annotatedWith("Foo").toInstance(foo);  // foo is an instance of FooImp

Then I guess now in my code wherever a Foo instance with a name annotation of "Foo" will be replaced by foo?

@Named("Foo")
Foo fooInst;   // fooInst will be foo at runtime?

If I'm right, how can I achieve this:

public Foo doSomething() {  // for some reason there must be no arguments
    @Named("Foo")
    Foo fooInst;   // injecting here seems not allowed...?
    fooInst.do();
}

Upvotes: 1

Views: 1757

Answers (3)

Jeff Bowman
Jeff Bowman

Reputation: 95614

The other answers are correct--you can only inject into the constructor, or into a field. It's standard practice to keep the instances as fields, which also allows you to swap in your own implementations for testing.

If you need to produce a new instance every time a method is called, you can use a Provider. For any given binding for Foo (or @Baz Foo), Provider<Foo> (or @Baz Provider<Foo>) is bound automatically without any extra code needed.

public class Bar {
  private Provider<Foo> fooProvider;

  @Inject
  public Bar(@Named("foo") Provider<Foo> fooProvider) {
    this.fooProvider = fooProvider;
  }

  public doSomething() {
    Foo foo = fooProvider.get();
  }
}

Of course, the way you have it with bind(...).toInstance(...), it will always be the same instance anyway, but should you need a new instance for every run of a method this is your best choice.

Upvotes: 0

RvanHeest
RvanHeest

Reputation: 869

What you are assuming is not completely right: Guice is used for dependency injection, which means that you can inject some interface/class into the constructor of another class.

Lets say you have an interface Foo and it's implementation FooImpl. Then you also have a class Bar which depends on an implementation of Foo.

public class Bar {

    private Foo foo;

    @Inject
    public Bar(@Named("foo") Foo foo) {
        this.foo = foo;
    }

    //some other methods
}

In your Guice-module you have to write

bind(Foo.class).annotatedWith(Names.named("Foo")).toInstance(foo);
//let's say this is part of the module MyModule extends AbstractModule

Once you set this up, you can make a main-method where you create an object by using Guice's Injector-class. Like so:

Injector injector = Guice.createInjector(new MyModule());
Bar bar = injector.getInstance(Bar.class);
//do something with bar

Hope this helped you with it. If you have more questions, feel free to ask me!

Hint: check the website of Guice, watch the video overthere and read the wiki carefully. Guice is a really great tool, but you need to do some study before you use it. Good luck!


Addition: In my opinion using @Named is a bad codestyle. You can better define your own annotations. For example:

@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface FooAnnotation {
}

Then replace @Named("foo") by @FooAnnotation in the Bar class and replace Names.named("Foo") by FooAnnotation.class in your module.

Upvotes: 5

micha
micha

Reputation: 49572

Unfortunatelly you cannot place annotations on local variables. This limitation comes from Java and not from Guice. According to this answer there is hope that we get this feature in future Java versions.

But please note that even if this would work it wouldn't be a good practice. The idea of dependency injection is the ability to change dependencies from outside of a class. A local variable does not fit into this because it cannot be changed from outside the class.

Upvotes: 1

Related Questions