14

can you get 2 singleton instances of the same underlying type?

this is obviously trivial in spring as it is based on named instances to which you attach a scope but I can't see the equivalent in guice which is about binding types to implementation classes. Note that I don't want to have to bind to the instance as the instances in question are injected with other dependencies by guice.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Matt
  • 8,367
  • 4
  • 31
  • 61

2 Answers2

17

I'd like to complement Marcin's response, by adding that you don't have to limit yourself to using toInstance() or provider methods in such a situation.

The following will work just as well:

bind(Person.class).annotatedWith(Driver.class).to(MartyMcFly.class).in(Singleton.class);
bind(Person.class).annotatedWith(Inventor.class).to(DocBrown.class).in(Singleton.class);

[...]

@Inject
public BackToTheFuture(@Driver Person marty, @Inventor Person doc) { ... }

Guice will inject the dependencies as usual when instantiating the MartyMcFly and DocBrown classes.


Note that it also works when you want to bind multiple singletons of the same type:

bind(Person.class).annotatedWith(Driver.class).to(Person.class).in(Singleton.class);
bind(Person.class).annotatedWith(Inventor.class).to(Person.class).in(Singleton.class);

For this to work, you must make sure that Person is not bound in the Singleton scope, either explicitely in the Guice module, or with the @Singleton annotation. More details in this Gist.

Edit: The sample code I give as an example comes from a Guice Grapher Test. Looking at the Guice tests is a great way to better understand how to use the API (which also applies to every project with good unit tests).

Etienne Neveu
  • 12,604
  • 9
  • 36
  • 59
  • Thanks Jesse :) The sample code I used to illustrate my point actually comes from a test for the Guice Grapher extension. I thought it was funny and pasted it as-is. I should have put a link to the source, though (I'll do that right now). As an aside, I love your blog and especially your practical articles on Guice / Google Collections ( http://publicobject.com/ ). We need more blogs like yours. So, thanks for this, too. – Etienne Neveu Oct 13 '09 at 12:28
  • @eneveu, you suggest that your solution is an alternative to Marcin's. It appears to me that the use case you describe is different than his, because yours assumes there are two different driver implementation classes (MartyMcFly, DocBrown), as opposed to two instances of one concrete (Driver) class. When I try to use this technique in the latter case, I get two references to the same singleton using this: `bind(MySingleton.class).annotatedWith(One.class).to(MySingleton.class).in(Singleton.class); bind(MySingleton.class).annotatedWith(Two.class).to(MySingleton.class).in(Singleton.class);` – Jeff Axelrod Aug 18 '11 at 16:25
  • It works for me. Maybe you annotated MySingleton with @Singleton? Here is an unit test with the various examples and explanations: https://gist.github.com/1156593 – Etienne Neveu Aug 19 '11 at 11:28
  • @JeffAxelrod I read the example differently, that `MartyMcFly` and `DocBrown` both extend `Person` class and the `@Driver` and `@Inventor` are [Binding Annotation](https://github.com/google/guice/wiki/BindingAnnotations) interfaces. The Guice FAQ's also show a [Private Modules solution](https://github.com/google/guice/wiki/FrequentlyAskedQuestions#how-do-i-build-two-similar-but-slightly-different-trees-of-objects) that seems to be better when e.g. the `BackToTheFuture` class needs to have the specific types instead of the base type (i.e. `BackToTheFuture(@Driver MaryMcFly driver,...)`). – Patrick M Mar 09 '15 at 19:22
16

It's easy in Guice too! Create two biding annotations, say @One and @Two and then

bind(MySingleton.class).annotatedWith(One.class).toInstance(new MySingleton());
bind(MySingleton.class).annotatedWith(Two.class).toInstance(new MySingleton());

and then

@Inject
public SomethingThatDependsOnSingletons(@One MySingleton s1,
    @Two MySingleton t2) { ... }
Marcin
  • 7,874
  • 7
  • 45
  • 49
  • or a @Provides method if it has dependencies, I missed this bit of the docs (http://code.google.com/docreader/#p=google-guice&s=google-guice&t=ProvidesMethods) Dependencies can be passed in as parameters to the method. The injector will exercise the bindings for each of these before invoking the method. – Matt Aug 03 '09 at 18:33
  • You don't need to bind it to an instance. Two different annotations to the same class, in scope singleton, will create two separate instances already. – Filip Dupanović Dec 15 '09 at 10:22
  • 2
    @Filip, I tried what you are suggesting, and received the same instance for both annotations. I used `bind(MySingleton.class).annotatedWith(One.class).to(MySingleton.class).in(Singleton.class); bind(MySingleton.class).annotatedWith(Two.class).to(MySingleton.class).in(Singleton.class);` – Jeff Axelrod Aug 18 '11 at 16:21