Yes; Guice does not yet have a hook so we can choose a different
constructor yet & invoke it from an extension. So only custom
field/method injections are possible right now.
> That means, I can make something like this:
>
> @Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
> @BindingAnnotation
> static @interface Property {
> String value();
> }
> /------------------------------------------------
>
> class PropertyProvider implements
> AnnotationMemberProvider<Property> {
>
> @Inject
> Registry registry;
>
> public Object provide(Property annotation, TypeLiteral<?>
> type, Field field) {
> return registry.get(annotation.value());
> }
>
> public Object provide(Property annotation, TypeLiteral<?>
> type, Method method, Class<?> parameterType, int parameterIndex) {
> return registry.get(annotation.value());
> }
>
> public boolean isNullParameterAllowed(Property annotation,
> Method method, Class<?> parameterType, int parameterIndex) {
> return false;
> }
> }
> /------------------------------------------------
> class Foo {
>
> @Property("foo-name")
> private final String name;
>
> }
Yes, that would work perfectly for field & method injection.
(BTW in trunk the API has changed a little bit from 2.0-beta-5 for the
AnnotationMemberProvider (mostly in the
AnnotationMemberProviderSupport class to be honest) to deal with all
the generics options on injection.
> That ok, but what about constructor injection?
>
> class Foo {
> private final String name;
>
> @Inject
> public Foo(@Property("foo-name") String name) {
> this.name = name;
> }
>
> }
>
> Custom annotations will not work in this case.
Yeah - I'm gutted we can't get constructor injection working with
custom annotations yet in Guice. Though its taken months of effort
just to get this far, so I'm kinda grateful we got some hooks in Guice
at last :)
> But I need to have constructor injection...
>
> Ok, my proposal is KeyedProvider.
>
> interface KeyedProvider<T> {
> String get(Key<T> key);
> }
>
> //----------------------------
>
> class PropertyProvider implements KeyedProvider<String> {
>
> @Inject
> Registry registry;
>
> public String get(Key<String> key) {
> final Property propertyAnnotation = (Property) key.getAnnotation
> ();
> return registry.get(propertyAnnotation.value());
> }
> }
>
> //--------------------------
>
> Module module = new AbstractModule() {
> protected void configure() {
> bind(String.class).annotatedWith
> (Property.class).toKeyedProvider(new PropertyProvider());
> }
> };
I've been having some similar thoughts lately.
A binding annotation can have values; if its got values you might want
to associate a specific set of values to a specific provider; or you
might want to bind all instances of the binding annotation to a kind
of provider - which is given the exact values of the annotation so it
can use those to create the value.
I wonder if Guice could be patched so that the InjectionPoint can be
injected into a provider?
using your original example
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@BindingAnnotation
static @interface Property {
String value();
}
you might want to do
bind(String.class).annotatedWith(Property.class).toProvider(MyPropertyLookup.class);
public clas MyPropertyLookup implements Provider<String> {
@Inject
InjectionPoint injectionPoint;
@Inject
Registry registry;
String get() {
Property property =
injectionPoint.getMember().getAnnotation(Property.class);
return registry.lookup(property.value());
}
}
That way there's no new APIs for Guice - its just that we'd need to
patch Guice to be able to inject the InjectionPoint thats about to be
injected into a provider? i.e. processing InjectionPoint in a special
way - like Injector.
The great thing is this would then allow regular Guice binding
annotations to have custom factories associated with them - or you
could still bind a specific instance of the annotation to a binding
using the regular approach.
BTW I hacked up a little test case to see if this even worked with
current Guice - but unfortunately it doesn't :(
http://code.google.com/p/guiceyfruit/source/browse/trunk/guiceyfruit-core/src/test/java/org/guiceyfruit/experiments/InjectionPointInjectTest.java
--
James
-------
http://macstrac.blogspot.com/
Open Source Integration
http://fusesource.com/
Injecting the Key would be fine too BTW :) as the key should have the
Annotation instance on it. I figured InjectionPoint might be useful
too - for example you might wanna use the field name as a default
property value if value is null.
Maybe injecting either?