xiaodududu / google-guice

Automatically exported from code.google.com/p/google-guice
Apache License 2.0
0 stars 0 forks source link

ProvisionListener doesn't report annotation in dependency chain #638

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
If a binding depends on a binding annotation, ProvisionListener doesn't report 
the annotation in the ProvisionInvocation's dependency chain. I've attached a 
program to exercise this.

Key[type=test.AnnotationProvisionListenerTest, annotation=[none]]
  Dependency: Key[type=test.AnnotationProvisionListenerTest, annotation=[none]], source: test.AnnotationProvisionListenerTest.class(AnnotationProvisionListenerTest.java:19)

Instead of [none], I would hope to see @Named("rose").

Original issue reported on code.google.com by vmaver...@google.com on 20 Jun 2011 at 4:48

Attachments:

GoogleCodeExporter commented 9 years ago
Looked into this a bit..  In the output, none of those [none]'s should be 
replaced by [@Named("rose")], because those are all outputs for provisioning 
AnnotationProvisionListenerTest, not the '@Named("rose") int'.  The reason the 
int isn't being printed is because Guice doesn't need to provision it -- it's 
already bound to a precreated instance.  toInstance bindings (which constant 
bindings necessarily are) don't need provisioning.

However, it is a little quirky with what's printed out -- take this test for 
example:

  private static class A1 {
    @Inject @Named("foo") B1 b;
    @Inject @Named("unknown") B1 b1;
  }  
  private static class B1 { }
  public void testAnnotations() {
    Injector injector = Guice.createInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(A1.class).annotatedWith(named("start")).to(A1.class);
        bind(B1.class).annotatedWith(named("foo")).to(B1.class);
        bind(B1.class).annotatedWith(Named.class).to(B1.class);
        bindListener(Matchers.any(), new ProvisionListener() {
          public <T> void onProvision(ProvisionInvocation<T> provision) {
           System.out.println("Provisioning: " + provision.getKey() + ", chain: " + provision.getDependencyChain() + "\n"); 
          }
        });
      }
    });
    injector.getInstance(Key.get(A1.class, named("start")));
  }

What's printed out is: 
 Provisioning: Key[type=com.google.inject.ProvisionListenerTest$A1, annotation=[none]], chain: [Dependency: Key[type=com.google.inject.ProvisionListenerTest$A1, annotation=@com.google.inject.name.Named(value=start)], source: com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:484), Dependency: Key[type=com.google.inject.ProvisionListenerTest$A1, annotation=[none]], source: com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:484)]

Provisioning: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=[none]], chain: [Dependency: 
Key[type=com.google.inject.ProvisionListenerTest$A1, 
annotation=@com.google.inject.name.Named(value=start)], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
484), Dependency: Key[type=com.google.inject.ProvisionListenerTest$A1, 
annotation=[none]], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
484), Dependency: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=@com.google.inject.name.Named(value=foo)]@com.google.inject.Provision
ListenerTest$A1.b, source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
485), Dependency: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=[none]], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
485)]

Provisioning: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=[none]], chain: [Dependency: 
Key[type=com.google.inject.ProvisionListenerTest$A1, 
annotation=@com.google.inject.name.Named(value=start)], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
484), Dependency: Key[type=com.google.inject.ProvisionListenerTest$A1, 
annotation=[none]], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
484), Dependency: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=@com.google.inject.name.Named(value=unknown)]@com.google.inject.Provi
sionListenerTest$A1.b1, source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
486), Dependency: Key[type=com.google.inject.ProvisionListenerTest$B1, 
annotation=[none]], source: 
com.google.inject.ProvisionListenerTest$16.configure(ProvisionListenerTest.java:
486)]

The first line is saying "I am creating a new unannotated A1", because 
@Named("start") A1 is linked to that.  The dependency hierarchy tells you that 
you're coming to A1 through @Named("start") A1.  The second line is basically 
the same, except for an unanottated B1 coming from @Named("start") A1 -> A1 -> 
@Named("foo") B1 -> B1

The third line is more the case you're looking for here.  It's saying "I am 
creating a new unannotated B1", the chain is:
  @Named("start") A1 -> A1 -> @Named("unknown") B1 -> B1

As near as I can tell, the only time the annotation in Provision.getKey() will 
be something other than 'none' is for Provider bindings, because all other 
bindings must ultimately link to an unannotated class or typeliteral.

Original comment by sberlin on 23 Jun 2011 at 3:47