extending:
http://developer.vz.net/2012/02/08/extending-guice-2/
http://forkbomb-blog.de/2012/slf4j-logger-injection-with-guice
https://github.com/google/guice/wiki/CustomInjections
https://spin.atomicobject.com/2012/01/13/the-guava-eventbus-on-guice/
annotations with value
http://stackoverflow.com/questions/28549549/guice-inject-based-on-annotation-value
https://github.com/google/guice/wiki/BindingAnnotations
public class MyAnnotations {
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER, ElementType.FIELD})
public @interface AutoConfig {
String value() default "abc";
}
}
public class AutoConfigImpl implements MyAnnotations.AutoConfig{
String value;
public AutoConfigImpl(String value) {
this.value = value;
}
@Override
public Class<? extends Annotation> annotationType() {
return MyAnnotations.AutoConfig.class;
}
@Override
public String value() {
return value;
}
public int hashCode() {
return (127 * "value".hashCode()) ^ value.hashCode();
}
public boolean equals(Object o) {
if (!(o instanceof MyAnnotations.AutoConfig)) {
return false;
}
MyAnnotations.AutoConfig other = (MyAnnotations.AutoConfig) o;
return value.equals(other.value());
}
private static final long serialVersionUID = 0;
}
public class UseHello {
final Hello hello;
@Inject
UseHello(@MyAnnotations.AutoConfig(value="def") Hello hello) {
this.hello = hello;
}
public Hello getHello() {
return hello;
}
}
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Hello.class).annotatedWith(new AutoConfigImpl("def")).to(Hello1.class);
bind(Hello.class).to(Hello2.class);
bind(Hello.class).annotatedWith(new AutoConfigImpl("abc")).to(Hello3.class);
}
});
System.out.println("hello is:" + injector.getInstance(UseHello.class).getHello().getMessage()); /// hello1
System.out.println("hello self is:" + injector.getInstance(Hello.class).getMessage()); // hello2
System.out.println("hello specificis:" +
injector.getInstance(Key.get(Hello.class, new AutoConfigImpl("abc"))).getMessage()); // hello3
if UseHello 's annotation is default, then injector.getInstance(UseHello.class).getHello().getMessage()) will be Hello3 as default value if "abc".
MiniGuice
A)
When a module is loaded, Guice basically create bindings from
Key.of(Bar.class, BarAnnotation.class) to a anonymous Provider, and it is put into: Map<Key, Provider<?» providersMap
B)
When Guice is bootstrapped in Jit for requiredKey(Foo.class) as the only initial element in requiredKeysQueue:
1) loop over requiredKey in the requiredKeysQueue.
1.1) for class of Foo (required key's type), if it is not in providersMap's key set yet, Guice will use reflection to gather fields, constructor.
1.1.1) Every field has an associated required key(FieldClass, annotation). It is put into Queue<Key> requiredKeysQueue.
1.1.2) for constructor, it examines injected constructor's parameters(constructor.getGenericParameterTypes(), constructor.getParameterAnnotations() ).
each parameter will have an associated required key(Parameter.class, annotation), which is put into requiredKeysQueue.
==> notice Provider<Bar> parameter is specially handled,
the required key is Key( xx.getActualTypeArguments()[0], key.annotation), where xx = constructor.getGenericParameterType = ParameterizedType.
for normal class, Parameter.class = Hello.class = constructor.getGenericParameterType
1.1.3) and a provider for the constructor on key(Foo.class, null_annotation) is also created and input into providersMap.
repeat the steps in step 1 until requiredKeysQueue is empty.
C)
for every key in providersMap, a provider's provider is also inserted. the new entry has key:
new ProviderType(javax.inject.Provider.class, key.type), key.annotation)
D)
then when it is required to create an instance of Foo.class,
1.1) it calls Foo constructor, where each parameter's key is searched in providersMap to create the parameter value.
1.2) each field is also injected by searching providersMap with field's key.
Notice of
@Inject Foo(Provide<Bar> bar) { // constructor
}
- in step B.1.1.2). the Key inserted into requiredKeysQueue is Key(Bar.class). not Key(Provider<Bar>.class).
- in step D 1.1), the parameter key will be ParameterizedType<Bar> and it is used to search providersMap , as
- ProviderType implements ParameterizedType
- ProviderType overrides getRawType to return Provider.class instead of ProviderType .class
- based on hashCode and equals of ProviderType. ParameterizedType<Bar> will match ProviderType instance key.
thus, the Provider's provider created in step C) is returned.