ProvisionListener bugs (several)
- Dominant language
- Java
- Stars
- 12.7k
- Forks
- 1.7k
- Avg merge
- 11m
- Merged PRs (30d)
- 2
Description
Guice v4.2.2
Sorry that I posted 3 bugs into one ticked but they can have common rootcause.
### Bug#1
As per documentation (javadoc for `ProvisionListener.onProvision`) provision listener for toInstance binding should appear at injections time. But in real it occurs when Injector created and does not occur when injection performed. See Console output and code below). As you can see `DO PROVISION #1` occurs st injection create time and does not occur when getInstance called and wnen invokeProviders() called.
Here javadoc for `ProvisionListener.onProvision`: (I marked important comments in bold)
> Invoked by Guice when an object requires provisioning. Provisioning occurs when Guice locates and injects the dependencies for a binding. For types bound to a Provider, provisioning encapsulates the Provider.get method. For toInstance or constant bindings, **provisioning encapsulates the injecting** of `@Injected` fields or methods. For other types, provisioning encapsulates the construction of the object. If a type is bound within a Scope, provisioning depends on the scope. Types bound in Singleton scope will only be provisioned once. **Types bound in no scope will be provisioned every time they are injected**.
### Bug#2
If we use binding to class with annotation:
```
bind(Obj.class).annotatedWith(Names.named("clazz")).to(Obj.class)
```
then inside `onProvision()` method we have wrong/corrupted Key for it. Actually information about annotation inside Key is null: provision.getBinding().getKey().getAnnotation() == null but should not. You can see that in lines with `DO PROVISION #3` and `DO PROVISION #10`
### Bug#3 (see at the bottom)
#### Console output.
```
Create injector #1 (MUST NOT invoke provision listeners)....
---> DO PROVISION #1 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=instance)] :: qa.MyModule.configure(MyModule.java:17)
Create injector #2....
---> DO PROVISION #1 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=instance)] :: qa.MyModule.configure(MyModule.java:17)
Get MyClass instance...
---> DO PROVISION #2 :: Key[type=qa.MyClass, annotation=[none]] :: class qa.MyClass
---> DO PROVISION #3 :: Key[type=qa.Obj, annotation=[none]] :: qa.MyModule.configure(MyModule.java:14)
---> DO PROVISION #4 :: Key[type=qa.Obj, annotation=[none]] :: qa.MyModule.configure(MyModule.java:14)
---> DO PROVISION #5 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=ctor)] :: qa.MyModule.configure(MyModule.java:20)
---> DO PROVISION #6 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=provider)] :: qa.MyModule.configure(MyModule.java:16)
Run invokeProviders...
provider: ---> DO PROVISION #7 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=provider)] :: qa.MyModule.configure(MyModule.java:16)
ctor : ---> DO PROVISION #8 :: Key[type=qa.Obj, annotation=@com.google.inject.name.Named(value=ctor)] :: qa.MyModule.configure(MyModule.java:20)
auto : ---> DO PROVISION #9 :: Key[type=qa.Obj, annotation=[none]] :: qa.MyModule.configure(MyModule.java:14)
class : ---> DO PROVISION #10 :: Key[type=qa.Obj, annotation=[none]] :: qa.MyModule.configure(MyModule.java:14)
instance:
Process finished with exit code 0
```
#### Source files (see download link at the bottom)
```java
public class GuiceTests {
public static void main(String[] args) {
MyModule myModule = new MyModule();
System.out.println("\nCreate injector #1 (MUST NOT invoke provision listeners)....");
Injector dummy = Guice.createInjector(myModule);
System.out.println("\nCreate injector #2....");
Injector injector = Guice.createInjector(myModule);
System.out.println("\nGet MyClass instance...");
MyClass instance = injector.getInstance(MyClass.class);
System.out.println("\nRun invokeProviders...");
instance.invokeProviders();
}
}
```
```java
public class MyClass {
@Inject Obj auto;
@Inject Provider autoProvider;
@Inject @Named("clazz") Obj clazz;
@Inject @Named("clazz") Provider clazzProvider;
@Inject @Named("provider") Obj provider;
@Inject @Named("provider") Provider providerProvider;
@Inject @Named("instance") Obj instance;
@Inject @Named("instance") Provider instanceProvider;
@Inject @Named("ctor") Obj ctor;
@Inject @Named("ctor") Provider ctorProvider;
public void invokeProviders() {
System.out.print("provider: ");providerProvider.get();
System.out.print("ctor : ");ctorProvider.get();
System.out.print("auto : ");autoProvider.get();
System.out.print("class : ");clazzProvider.get();
System.out.print("instance: ");instanceProvider.get();
}
}
```
```java
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(Obj.class);
bind(Obj.class).annotatedWith(Names.named("clazz")).to(Obj.class);
bind(Obj.class).annotatedWith(Names.named("provider")).toProvider(Obj::new);
bind(Obj.class).annotatedWith(Names.named("instance")).toInstance(new Obj());
try {
bind(Obj.class).annotatedWith(Names.named("ctor")).toConstructor(Obj.class.getConstructor());
} catch (NoSuchMethodException ex) {ex.printStackTrace();}
bindListener(Matchers.any(), new MyProvisionListener());
}
public static class MyProvisionListener implements ProvisionListener {
private AtomicInteger counter = new AtomicInteger(0);
@Override
public void onProvision(ProvisionInvocation provision) {
System.out.println(" ---> DO PROVISION #" + counter.incrementAndGet() +
" :: " + provision.getBinding().getKey() +
" :: " + provision.getBinding().getSource());
Object provisioned = provision.provision();
}
}
}
```
### Bug#3
Sometimes ProvisionListener does not work when I create binding to '.class' with annotation or when I use 'default' binding. Neither when I `@Inject object` nor when I use `@Inject Provider provider` and then call `provider.get()`
I cannot reproduce that in project which I attached but in my main project the listener is not invoked. But I found that if I define explicit bindind (like `bind(MyClass.class)`) it 'fixes' issue. But of cause I cannot use that as workaround. See attached screenshots.


[guicetest.zip](https://github.com/google/guice/files/3567044/guicetest.zip)
Contributor guide
Assessment
This issue has not been assessed yet.