Using ProvisionListener to Find Bindings in(Singleton.class)

548 views
Skip to first unread message

jwa

unread,
Nov 3, 2015, 2:01:46 PM11/3/15
to google-guice
Hi All,

I'd like to write a provision listener which is capable of identifying instances of singletons when they're provisioned. Specifically singletons that are bound in a module using in(Singleton.class).

However, using the helper method Scopes.isSingleton(...) does not appear to be correctly identifying singletons bound in this fashion.

Here is a demonstration of the problem I am encountering:

public interface Vehicle { }
public static class Car implements Vehicle { }

public static void main(String[] args) {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Vehicle.class).to(Car.class).in(Singleton.class);
bindListener(Matchers.any(), new ProvisionListener() {
@Override
public <T> void onProvision(ProvisionInvocation<T> provision) {
System.out.println(provision.getBinding().getKey() + " is singleton = " + 
Scopes.isSingleton(provision.getBinding()));
}
});
}
});
injector.getInstance(Vehicle.class);
}



If I execute this I get the following console output:

Key[type=com.instinet.gtr.cucumber.caas.di.TestGuice$Car, annotation=[none]] is singleton = false

Am I missing something? This seems to be incorrectly reporting that the provision was not a singleton?

Any tips would be greatly appreciated.

Thanks!

P.S. Guice 4.0

Thomas Broyer

unread,
Nov 3, 2015, 4:17:05 PM11/3/15
to google-guice
The Car binding isn't a Singleton; the Vehicle one is. Using separate bind() calls might do what you want:

bind(Vehicle.class).to(Car.class);
bind(Car.class).in(Singleton.class);

(I don't know listeners much so can't really help beyond the above)

Jamie Astin

unread,
Nov 3, 2015, 6:11:42 PM11/3/15
to google...@googlegroups.com

Hi Thomas,

Thanks for taking the time to reply. The output posted is the total output from my test.

Therefore, Guice is only observing one provision. Thus, its not like theres a second provision I could inspect.

Also, the modules I'm consuming are provided by application developers who use my framework. I've published in the API they need to produce Guice modules. I'm not willing to be more restrictive and tell them to use specific syntax, that would reflect poorly on my framework.

If the two separate bindings do work, this surely suggests a Guice bug? As far as I can tell your two-liner should be functionally equivalent to my on-liner?

I'll try the two-liner tomorrow. My intention would be to debug + raise a bug / pull request if it actually fixes the underlying problem... Unless someone can explain the disparity between the one/two-liner?

Thanks again!

--
You received this message because you are subscribed to a topic in the Google Groups "google-guice" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-guice/c2Gt_ABD7cQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-guice/b0d87ebc-b473-4b1b-97da-ec85f5755b5a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alexander Openkowski

unread,
Nov 4, 2015, 3:05:55 AM11/4/15
to google...@googlegroups.com

Also, the modules I'm consuming are provided by application developers who use my framework. I've published in the API they need to produce Guice modules. I'm not willing to be more restrictive and tell them to use specific syntax, that would reflect poorly on my framework.

You could provide an abstract Guice module to hide the tedious binding procedure from developers using your framework. See for example:

https://github.com/ArcBees/GWTP/blob/master/gwtp-core/gwtp-mvp-client/src/main/java/com/gwtplatform/mvp/client/gin/AbstractPresenterModule.java#L49
You received this message because you are subscribed to the Google Groups "google-guice" group.

To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.


To post to this group, send email to google...@googlegroups.com.

Visit this group at http://groups.google.com/group/google-guice.

jwa

unread,
Nov 4, 2015, 4:13:02 AM11/4/15
to google-guice
Thomas - Having re-read your response I understand what you are alluding to; the two-liner you are suggesting makes the Car a singleton within the Injector. I can confirm that if I change the binding to your suggested two-liner it does indeed note the provisioned Car is a singleton, i.e.

bind(Vehicle.class).to(Car.class);
bind(Car.class).in(Singleton.class);

Will output:

Key[type=com.instinet.gtr.cucumber.caas.di.TestGuice$Car, annotation=[none]] is singleton = true

However, that is not functionally equivalent to my previous module configuration. I am happy for multiple Cars to exist in the system, I simply want every instance of Car that is injected to fulfill Vehicle to use the same instance.

---

Using the TypeListener and ProvisionListener SPI mechanisms I am unable to observe any information about Vehicle, I am only notified about the type Car. Therefore, it seems impossible to observe the fact that the binding of Vehicle is within Singleton scope?

@opn - A valid point, I hadn't considered the syntactic sugar I could offer with my own domain-specific abstract module. That's an idea which is useful in numerous places.

Thanks Again.

jwa

unread,
Nov 4, 2015, 5:05:31 AM11/4/15
to google-guice
I have come up with a solution that allows me to find all of the Singleton bindings in the module using the bind(...).in(Singleton.class) using the SPI mechanisms for introspecting a *Module* and not an *Injector*. 

To modify my previous example code:

AbstractModule mod = new AbstractModule() {
  @Override
  protected void configure() {
    bind(Vehicle.class).to(Car.class).in(Singleton.class);
  }
};

Elements.getElements(mod).forEach((e) -> {
  e.acceptVisitor(new DefaultElementVisitor<Void>() {
      public <T> Void visit(Binding<T> binding) {
        if (Scopes.isSingleton(binding)) {
          System.out.println(binding.getKey() + " is singleton = " + Scopes.isSingleton(binding));
        }
        return null;
      }
  });
});

This correctly observes that the binding of Vehicle is a singleton:

Key[type=com.instinet.gtr.cucumber.caas.di.TestGuice$Vehicle, annotation=[none]] is singleton = true

Sam Berlin

unread,
Nov 4, 2015, 9:08:33 AM11/4/15
to google-guice

The lack of notification for linked bindings is by design. ProvisionListener only notifies things that are provisioned (essentially the right hand side of any linked binding).

This does have a bad side effect of dropping some scoped notifications, though, and folks probably aren't expecting that. I had thought it was mentioned in the javadocs, but looks like it isn't.

At the very least, I can mention it in the docs.  I'm less enthused about notifying on linked bindings too, but maybe that's not so terrible.

sam


Reply all
Reply to author
Forward
0 new messages