1

I would like to bind a unique singleton instance for each annotation as shown below, such that Client1.a != Client1.b and Client1.a == Client2.a.

class X {}

@Singleton class OneOfEachAnnotation { 
   @Inject OneOfEachAnnotation(X x) { }
}

class Client1 {
   @Inject Client(@A OneOfEachAnnotation a, @B OneOfEachAnnotation b) {}
}

class Client2 {
   @Inject Client(@A OneOfEachAnnotation a, @B OneOfEachAnnotation b) {}
}

This answer seems to claim that I can accomplish the binding like this, but when I do so, Client1.a == Client1.b.

bind(OneOfEachAnnotation.class).annotatedWith(A.class).to(OneOfEachAnnotation.class).in(Singleton.class);
bind(OneOfEachAnnotation.class).annotatedWith(B.class).to(OneOfEachAnnotation.class).in(Singleton.class);
Community
  • 1
  • 1
Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246

1 Answers1

3

Thanks to Sam Berlin at Google Groups Guice forum. The reason this doesn't work is because the OneOfEachAnnotation is already annotated with @Singleton. Removing the @Singleton annotation fixes the problem.

Sam explained why:

The statements:

bind(OneOfEachAnnotation.class).annotatedWith(A.class).
 to(OneOfEachAnnotation.class).in(Singleton.class);
bind(OneOfEachAnnotation.class).annotatedWith(B.class).
 to(OneOfEachAnnotation.class).in(Singleton.class);

are saying, "Create a binding from @A OneOfEachAnnotation to OneOfEachAnnotation and make the @A OneOfEachAnnotation a singleton." Same thing with @B.

Ignoring the @Singleton on OneOfEachAnnotation for a second (assuming it didn't exist), then this would have the behavior of:

  • User injects OneOfEachAnnotation (unannotated) multiple times: a new one is created each time, because that binding is unscoped.

  • User injects @A OneOfEachAnnotation, the first time it links down to the unannotated OneOfEach, sees it needs to be constructed, and constructs it. The second time the binding is already provisioned, so Scopes.SINGLETON doesn't go to the linked binding again. (Same thing with @B as @A.)

When OneOfEachAnnotation has @Singleton on it, then Guice thinks that the unscoped value is also a singleton. So when @A links to the unannotated, it will create the first instance. When @B links down the unannotated, Guice notices that the unannotated version, also a Singleton, has already been constructed, and returns that instance.

Jeff Axelrod
  • 27,676
  • 31
  • 147
  • 246