class foo {
@Inject @SomeResourceLikeThing("pathToTheResource") SomeResource
resource;
}
More or less I want to be able to inject a resource (think a file,
Lucene index, etc) where the value of the annotation points at the
resource to inject. I've come up with three possible solutions and I
like the last one the best:
1. I could inject a builder type object and build the resource that
way.
2. I could write some code like
configure() {
binder.bind(SomeResource.class).annotatedWith(new
NamedAnnotation("pathToTheResource"))
.toProvider(new
SomeResourceLikeThingProvider("pathToTheResource"));
}
but that has several problems. Besides being very verbose, I need to
do that for each and every resource and SomeResourceLikeThingProvider
is no longer "in the club" (not to mention that now
"pathToTheResource" appears in at least three different places).
3. What I'd really like is to write something like
configure() {
binder.bind(SomeResource.class).annotatedWith(SomeResourceLikeThing.class)
.toProvider(SomeResourceLikeThingProvider.class));
}
where the value of the annotation is passed in to the provider at
runtime or, in the alternative, the provider is given a handle to the
Field/Method/Constructor being injected so I can look up the value on
my own.
Am I approaching this in entirely the wrong direction, is anything
like this currently possible or am I going to have to wait for the
result of the customized @Inject/post processor debate and whatever
feature that results in 1.1?
Thanks,
--Chris
>I've been looking into using annotations with values ...
> @Inject @SomeResourceLikeThing("pathToTheResource") SomeResource ...
you probably know this, but just in case, junit4 does something like this with:
@Test(expected= IndexOutOfBoundsException.class) public void empty() {
new ArrayList<Object>().get(0);
}
thanks
---
vice-chair http://ocjug.org/
In general I think I agree with what you're saying, however I think I
may have been too general and not explained my use case correctly. I
think that because I don't understand how this comment applies to what
I want to do:
"The point Im trying to make is that the instance binding belongs in
module
or Provider code not in metadata (then it becomes difficult to change
the
impls for testing/redeployment etc.). "
To be very concrete with an example, imagine I'm adding search support
to an application. I'm using Lucene as my underlying IR library and
there are twelve distinct indexes I'm going to need to support all my
use cases. What I'd like to see in my code is something like
class UserSearchController {
@Inject @LuceneSearch("/indexes/users") Search userSearch;
}
class FooSearchController {
@Inject @LuceneSearch("/indexes/foo") Search fooSearch;
}
etc.
I follow your point with having an annotation and provider for each
case but in my mind that doesn't really seem to scale. In my use case
I'd need 12 annotations and 12 providers and, for all intents and
purposes, the only difference between the providers is a string
constant. The SpringIntegration basically suffers from exactly this
same problem, it can just hide it since getting a list of spring beans
is possible at runtime so it generates all the bindings in code. If,
in order to use SpringIntegration, you needed to create an annotation
+ provider per bean I'd say that it is useless in practice. Even
needing to hand create a binding to a named annotation for each
possible spring bean can quickly become problematic (think of an
application with a hundred or two spring beans, your module code would
become ridiculously long). For either my use case or the
SpringIntegration use case, however, if the provider got access to the
value in the annotation then there would only need to be a single
binding and a single provider. The provider could use the metadata in
the annotation to respond to the get method.
I don't see how I am making testability any harder since I'm not
depending on any concrete classes in my code, the provider still
creates the concrete instance, it just uses a piece of metadata to
make it's job a little easier.
Lastly, I'm not claiming that there isn't an easier or more Guicey way
of dealing with this, I'm just trying to find out what people who know
more than me think. It seems that by supporting values in annotations
at all that Guice is getting us most of the way there, it's just this
last piece that I'm not seeing how to do cleanly.
Thanks for your input
--Chris
On May 1, 12:30 am, "Dhanji R. Prasanna" <dha...@gmail.com> wrote:
> Ok this is really getting into hacking territory now. Guice uses annotations
> to denote wiring hooks within the code only.
> Imo, guice does not encourage configuration data within annotations. What
> you want is *much* better in module code, either as you suggested with
> multiple bindings or better, multiple keys and providers:
>
> @Inject @SomeResourceAtPathA SomeResource res;
>
> //module
> bind(SomeResource.class).annotatedWith(SomeResourceAtPathA.class
> ).toProvider(SomeResourceAtPathAProvider.class);
>
> Then in the provider:
> class SomeResourceAtPathAProvider impls Provider<SomeResource> {
> @Inject @Named("pathA") String pathA;
> //etc.
>
> }
>
> Using the annotation's value to specify an instance (in this case of String)
> is no different to:
> @Inject @MyInject(MyInstanceProvider.class) Service service;
>
> The point Im trying to make is that the instance binding belongs in module
> or Provider code not in metadata (then it becomes difficult to change the
> impls for testing/redeployment etc.).
>
> Having said that however, you can hack your way to your solution (and I *do*
> mean hack) by splitting up your provider in this unholy manner:
>
> bind(SomeResource.class).annotatedWith(new NamedAnnotation("path")).to(
I tried to post a response last night and it appears to have never
made it. Oh well, I hope I remember what I was going to say.
To be very concrete with an example, imagine I'm adding search support
to an application. I'm using Lucene as my underlying IR library and
there are twelve distinct indexes I'm going to need to support all my
use cases. What I'd like to see in my code is something like
class UserSearchController {
@Inject @LuceneSearch("/indexes/users") Search userSearch;
}
class FooSearchController {
@Inject @LuceneSearch("/indexes/foo") Search fooSearch;
}
I follow your point with having an annotation and provider for each
case but in my mind that doesn't really seem to scale.
If,
in order to use SpringIntegration, you needed to create an annotation
+ provider per bean I'd say that it is useless in practice. Even
needing to hand create a binding to a named annotation for each
possible spring bean can quickly become problematic (think of an
application with a hundred or two spring beans, your module code would
become ridiculously long).
For either my use case or the
SpringIntegration use case, however, if the provider got access to the
value in the annotation then there would only need to be a single
binding and a single provider. The provider could use the metadata in
the annotation to respond to the get method.
I'm just trying to find out what people who know
more than me think. It seems that by supporting values in annotations
at all that Guice is getting us most of the way there, it's just this
last piece that I'm not seeing how to do cleanly.
> LuceneSearch annotation
> = (LuceneSearch) injectionPoint.getBindingAnnotation();
Are you allowed to have multiple annotations on an injection? The
language allows that syntactically, but I don't know if Guice does
anything to detect and prevent it. If not, you might need to change
the API to look more like:
LuceneSearch annotation =
injectionPoint.getBindingAnnotation(LuceneSearch.class);
Actually that might be preferable anyway because it's more type safe.
-- Laura
@Authorized (roles="boss")
public interceptorProtectedMethod(...){
... hireSomePeople...:)
}
and in the Interceptor
public Object invoke(MethodInvocation i) throws Throwable {
... i.getMethod().getAnnotations() // do the magic}
InjectionPoint looks cool, but maybe Annotation[] would do the trick?
Something like
interface Provider<T>{
T get(Annotation[] annotations);}
then you can do
@Inject
@ExtraAnnotation (filename="test.txt")
private File file;
and then in FileProvider implements Provider<File>
File get(Annotation[] annotations){
ExtraAnnotation extra = ... get from annotations;
return new File(extra.filename());}
Normally you would just ignore the Annotation[], just my 2 cents.