Binding annotations with parameters

1,195 views
Skip to first unread message

Aleksey Didik

unread,
Apr 10, 2009, 4:35:09 AM4/10/09
to google-guice
Hello all,
I have caught one problem and want to ask your advise.

In the my application I have a registry singleton which contains all
application properties

class Registry {
String get(String property) {
//stub
return "Foo";
}
}

Some components of my app need the Registry to work (is a component
enabled,
connection timeout and etc), but I don't want to inject the Registry
itself, it will make components harder to test and not only. I want
to
inject properties values from the Registry.
I have found the Names.bindProperties() solution in Guice FAQ, but
it's not for me;
properties in the Registry is not immutable.

The best for me is using an annotation like @Property("foo.name") and
using the Registry to resolve annotated dependency.

class Foo {
@Property("foo-name")
private String name;
}

With last Guice update I can use a listener binding and register
MembersInjector in TypeEncounter. MembersInjector allow me to resolve
all necessary dependencies by myself.
But it's works only for methods and fields, but I'm a constructor
injection adept and I want to use a parametrized annotation in
constructor, for example:

class Foo {
private final String name;
@Inject
public Foo(@Property("foo-name") String name) {
this.name = name;
}
}

Using Provider can't solve my issue, because Provider.get() has no
information about the dependency injected now.

My proposal is adding to Guice something like 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());
}
};


As to me, it will be very usefull. We can use binding annotations not
only as markers, but as a set of parameters, as what and how provide
now.

What do you think about it?

Best regards,
Aleksey.

irium

unread,
Apr 10, 2009, 9:53:33 AM4/10/09
to google-guice
+1 for that. I'm also need for similar feature and it will be very
useful to be implemented in Guice.

James Strachan

unread,
Apr 10, 2009, 12:09:34 PM4/10/09
to google...@googlegroups.com
2009/4/10 irium <iriu...@gmail.com>:

> +1 for that. I'm also need for similar feature and it will be very
> useful to be implemented in Guice.

Agreed - I think its a great idea. A binding annotation that has
values can be bound via its type or via an exact combination of values
- but there's currently no way if you bind to a type of annotations to
get the actual values and use those in your provider method.

This came up recently on the guiceyfruit list...
http://groups.google.com/group/guiceyfruit/browse_thread/thread/da948ae7d48bb99

One idea to implement this without adding new APIs, is to allow
details of an injection point to be injected into providers. e.g. to
allow the Key/InjectionPoint to be injected into a Provider.

As well as the annotation instance; a provider might want to access
the Member as well (e.g. to use the name of the field/method as an
extra default value - for example for lookups into registries and
whatnot). I was wondering if InjectionPoint was a natural choice for
something we might want to make injectable into a Provider? Doesn't
quite work if a parameter to a constructor/method has annotations etc
but at least it would let providers see the member name & other
annotations etc?

--
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://fusesource.com/

Bob Lee

unread,
Apr 10, 2009, 2:22:16 PM4/10/09
to google...@googlegroups.com
I understand that the values are mutable at run time, but do you know the set of keys up front?

I would create a binding for each key:

  for (final String key : keys) {
    // replace @Named w/ @Property equivalent
    bind(String.annotatedWith(Names.named(key))).toProvider(new Provider<String>() {
      @Inject Registry registry;
      public String get() {
        return registry.get(key);
      }
    });
  }

You might scope the result, too, so the value doesn't change in the middle of an HTTP request for example.

If you don't already have a way to determine the set of keys at load time, you can run an annotation processor (http://java.sun.com/javase/6/docs/api/javax/annotation/processing/Processor.html) over your code that finds the @Property annotations and writes the keys to a file.

The benefit of this approach is that you can check your code at build or initialization time.

Bob

Aleksey Didik

unread,
Apr 13, 2009, 6:42:08 AM4/13/09
to google-guice
Thank you Bob, you are right.
Properties keys are immutable and I can use your solution.

Many thanks,
Aleksey.



On Apr 10, 11:22 pm, Bob Lee <crazy...@crazybob.org> wrote:
> I understand that the values are mutable at run time, but do you know the
> set of keys up front?
>
> I would create a binding for each key:
>
>   for (final String key : keys) {
>     // replace @Named w/ @Property equivalent
>     bind(String.annotatedWith(Names.named(key))).toProvider(new
> Provider<String>() {
>       @Inject Registry registry;
>       public String get() {
>         return registry.get(key);
>       }
>     });
>   }
>
> You might scope the result, too, so the value doesn't change in the middle
> of an HTTP request for example.
>
> If you don't already have a way to determine the set of keys at load time,
> you can run an annotation processor (http://java.sun.com/javase/6/docs/api/javax/annotation/processing/Pro...)
> over your code that finds the @Property annotations and writes the keys to a
> file.
>
> The benefit of this approach is that you can check your code at build or
> initialization time.
>
> Bob
>
Reply all
Reply to author
Forward
0 new messages