Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting named Guice singleton

I have a simple POJO:

public class MyPOJO {
    @Inject
    private Fizz fizz;

    private Buzz buzz;

    // rest of class omitted for brevity
}

I would like to configure my Guice module such that there are two types of Fizzes that it injects:

  1. A special, globally-singleton Fizz instance; and
  2. Other (non-special) Fizz instances

I want MyPOJO to be injected with the special/singleton instance. So I modified my code:

public class MyPOJO {
    @Inject @Named("Special-Fizz")
    private Fizz fizz;

    private Buzz buzz;

    // rest of class omitted for brevity
}

Then in my module:

public class MyModule extends AbstractModule {
    @Override
    public void configure() {
        bind(Fizz.class).annotatedWith(
            Names.named("Special-Fizz"))
            .to(Fizz.class);

        // Other bindings here...
    }

    @Provides @Singleton
    private Fizz providesFizz() {
        return new Fizz(true, "Special", 12.0);
    }
}

But when I try to unit test (JUnit 4.10) this:

public class MyTest {
    @Named("Special-Fizz") private Fizz specialFizz;

    @Test
    public void usingNamedShouldInjectSpecialFizz() {
        MyModule mod = new MyModule();
        Injector injector = Guice.createInjector(mod);

        specialFizz = injector.getInstance(Fizz.class);

        Assert.assertTrue(specialFizz != null);
    }
}

This passes. So far, so good. But then if I change the name of the specialFizz field:

    @Named("Special-Fuzz-This-Shouldnt-Work") private Fizz specialFizz;

And re-run the test, it still passes. Why?!? Where am I going astray here? Thanks in advance.

like image 811
IAmYourFaja Avatar asked Feb 08 '13 21:02

IAmYourFaja


People also ask

What is singleton in Guice?

Annotation Type SingletonApply this to implementation classes when you want only one instance (per Injector ) to be reused for all injections for that binding.

What does @inject do Guice?

Note that the only Guice-specific code in the above is the @Inject annotation. This annotation marks an injection point. Guice will attempt to reconcile the dependencies implied by the annotated constructor, method, or field.

How do you inject a Guice class?

The implementation is very easy to understand. We need to create Injector object using Guice class createInjector() method where we pass our injector class implementation object. Then we use injector to initialize our consumer class. If we run above class, it will produce following output.

What is @inject annotation in Guice?

Annotation Type Inject. @Target(value={METHOD,CONSTRUCTOR,FIELD}) @Retention(value=RUNTIME) @Documented public @interface Inject. Annotates members of your implementation class (constructors, methods and fields) into which the Injector should inject values.


2 Answers

Very odd. Guice should complain if it can't find a Named binding that it's injecting. I'm a bit confused by your test, though. I don't know what injector.inject does. Do you mean injectMembers? It might make more sense to actually get an instance of your POJO and make sure that it's working the way you expect. Maybe something like:

public class FizzTest {

  public static class MyModule extends AbstractModule {
    @Override
    protected void configure() {
    }

    @Provides
    @Singleton
    @Named("Special-Fizz")
    public Fizz providesFizz() {
      return new Fizz(true);
    }
  }

  public static class Fizz {
    boolean special = false;
    public Fizz() {}
    public Fizz(boolean special) {
      this.special = special;
    }
  }

  public static class MyPOJO {
    @Inject @Named("Special-Fizz")
    private Fizz fizz;

    @Inject
    private Fizz otherFizz;
  }

  @Test
  public void test() {
    MyModule mod = new MyModule();
    Injector injector = Guice.createInjector(mod);

    MyPOJO pojo = injector.getInstance(MyPOJO.class);
    assertTrue(pojo.fizz.special);
    assertTrue(!pojo.otherFizz.special);
  }

}
like image 165
condit Avatar answered Sep 21 '22 04:09

condit


Guice sees the @Provides method and happily uses that to inject the Fizz. If you want to have a special instance of Fizz, you can drop the annotations from the providesFizz() method and instead bind with

bind(Fizz.class)
    .annotatedWith(Names.named("Special-Fizz")
    .toInstance(providesFizz());

This way, you tell Guice exactly which Fizz to use as the "Special-Fizz", while still letting it inject Fizz "normally" otherwise.

Disclaimer: I haven't actually tried a setup like yours, but I have used one similar. Let me know if it works or not.

like image 42
Bradley T. Hughes Avatar answered Sep 18 '22 04:09

Bradley T. Hughes