28

I have a provider method in a module annotated with @Provides:

@Provides
public ChatServicePerformanceMonitor getChatServicePerfMon() {
  ...
}

and I have annotated my ChatServicePerformanceMonitor with @Singleton. In my code, where I use this instance, I can't have guice "passively" inject it, due to a framework I'm using that's constructing the enclosing class (it does not use Guice, so this is the only way I know of to get the reference):

chatServicePerfMon = injector.getInstance(ChatServicePerformanceMonitor.class);

It seems Guice does not respect the @Singleton annotation on my ChatServicePerformanceMonitor class. I get an instance for every call to injector.getInstance(ChatServicePerformanceMonitor.class).

Adding the @Singleton to the provider method seems to fix this:

@Provides @Singleton
public ChatServicePerformanceMonitor getChatServicePerfMon() {
  ...
}

Is that the expected behavior? It seems an @Singleton on the instance should be all I would need.

Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
Alper Akture
  • 2,445
  • 1
  • 30
  • 44
  • 2
    How are you creating the `ChatServicePerformanceMonitor` in your first code snippet? If Guice isn't creating it inside your `getChatServicePerfMon` method then the `@Singleton` will be ignored. – condit Apr 11 '13 at 19:54
  • 1
    Yes, it's constructed inside that @Provider method, almost exactly as described [here](https://code.google.com/p/google-guice/wiki/ProvidesMethods) in the provideTransactionLog method. Seems like it must be something I'm doing, as someone else must have had this issue. But I can't see anything that's not really different from their examples, other than I'm getting the instance directly from an injector. – Alper Akture Apr 11 '13 at 20:18

3 Answers3

31

In the meantime this feature is available (tested with Guice 4.0).

@Provides methods may now be also annotated with @Singleton to apply scope. See https://github.com/google/guice/wiki/Scopes

codejanovic
  • 522
  • 5
  • 9
23

If you're creating the ChatServicePerformanceMonitor like this:

@Provides
public ChatServicePerformanceMonitor getChatServicePerfMon() {
  return new ChatServicePerformanceMonitor();
}

then your class level @Singleton annotation will have no effect because Guice isn't creating the object, you are. Guice can only enforce scope on objects it creates. There's nothing wrong with adding @Singleton to your getChatServicePerfMon() method.

If you have a no-argument constructor (or an @Inject constructor) on the ChatServicePerformanceMonitor class and you remove your @Provides method then continual calls to the injector will return the same singleton.

Adam Peck
  • 6,930
  • 3
  • 23
  • 27
condit
  • 10,852
  • 2
  • 41
  • 60
  • 2
    Ok, thanks. I am doing a new in there. I guess since Guice is calling my provider method, I thought it would still enforce the Singleton behavior (since I don't call the provider method, they do) and could manage that. Guess I was wrong! – Alper Akture Apr 11 '13 at 22:27
  • I don't know which framework you're using but you could also use Guice to create the enclosing instance (even though you can't inject into it) via a `Provider` (or `@Provides`). That way that object can collaborate with other Guice dependencies. – condit Apr 11 '13 at 22:51
  • Thansk, yes, i dug around for a way to do that for a while, but the way this framework "works" is I extend one of their classes. They bootstrap everything when they startup (it's a game server called SmartFox), and they do the extension class instantiation. I don't think there's a way to have Guice intercept that, is there? – Alper Akture Apr 11 '13 at 23:16
  • 6
    As a rule of thumb: When using DI/Guice, never use the word "new". – Jan Galinski Apr 14 '13 at 07:25
  • "Guice can only enforce scope on objects it creates" Guice is creating the object. It's just calling our `Provides` method instead of calling the class constructor. I see no reason why it couldn't honor the `@Singleton` class annotation in this case. – Eric Nov 15 '19 at 18:07
-5

You could always just do the dead-simple approach:

private ChatServicePerformanceMonitor perfMon = null;

@Provides
public ChatServicePerformanceMonitor getChatServicePerfMon() {
  if (perfMon == null) {
    perfMon = new ChatServicePerformanceMonitor();
  }

  return perfMon;
}
Tim Keating
  • 6,443
  • 4
  • 47
  • 53