-
1. Re: Generic Typed Injection by Class at Runtime, how?
alesj Nov 9, 2011 9:44 AM (in response to ahhughes)See how TypeLiteral is used in CDI.
-
2. Re: Generic Typed Injection by Class at Runtime, how?
alesj Nov 9, 2011 9:47 AM (in response to ahhughes)
@Inject Instance<PlaceTokenizer> tokenizers;
PlaceTokenizer<MyPlace> = tokenizers.select(new TypeLiteral<MyPlace>{}).get(); -
3. Re: Generic Typed Injection by Class at Runtime, how?
ahhughes Nov 9, 2011 5:23 PM (in response to ahhughes)Hi Ales,
Thank you for your replies. Unfortunately, I don't think your advice will resolve my problem, because the TypeLiteral annonymous class requires MyPlace and not thePlace.getClass(). Effectively, this still leaves me with only a 'compile time' solution.... and I can solve that with @Inject MyPlaceTokenizer<MyPlace>... erasure shows its head again :'( The only solution I can find at the moment is to associate MyPlace to MyPlaceTokenizer via a @PlaceQualifier(name="MyPlace") qualifier. If I want to secure this any more, I will need to write a CDI extension to scan for each of the Bean Types, and see that there is a 1:1 binding/association.
headache++;
Ales Justin wrote on Nov 09, 2011 09:47:
@Inject Instance<PlaceTokenizer> tokenizers;
PlaceTokenizer<MyPlace> = tokenizers.select(new TypeLiteral<MyPlace>{}).get();Click HELP for text formatting instructions. Then edit this text and check the preview.
I have two vague ideas floating in my head (and I doubt either will work cleanly):
1. Qualifiers : The problem here is that if I re-use a common qualifier @PlaceQualifier on all Place objects, then -
4. Re: Generic Typed Injection by Class at Runtime, how?
ahhughes Nov 9, 2011 5:56 PM (in response to ahhughes)whoops, I half deleted what I was going to write at the end... I might as well say it now...
I have two vague ideas floating in my head (and I doubt either will work cleanly): 1. Qualifiers : The problem here is that if I re-use a common qualifier @PlaceQualifier on all Place objects, then...
Continued...
Qualifiers don't help me at compile time. I can't strictly type/bind to MyPlace/MyPlaceTokenizer using qualifiers, because there is nothing from binding YourPlace / MyPlace...
@PlaceQualifier(placeClass=MyPlace.class)
public class YourPlaceTokenizer implements PlaceTokenizer<YourPlace> { ... }So... tokenizers.select(new PlaceQualifierLiteral(instanceOfMyPlace.getClass())); will return a PlaceTokenizer<YourPlace> and not PlaceTokenizer<MyPlace> This leads to other issues of course :'(
Other vague idea I had was to try and register the beans with a custom CDI extension. But this is little merit as erasure will again prevent the extension from determining the type of generic arguments at runtime.
Either way
headache++; -
5. Re: Generic Typed Injection by Class at Runtime, how?
ahhughes Nov 30, 2011 10:59 PM (in response to ahhughes)This is the best I can come up with....
Create a Qualifier (binding by Place class)
@Qualifier @Target({ METHOD, FIELD, PARAMETER, TYPE }) @Retention(RUNTIME) public @interface PlaceTyped { Class<? extends Place> value(); }
Create a Literal for the Qualifier
This is used to obtain a PlaceTyped (Qualifier) at runtime for programmatic lookup.
public class PlaceTypedLiteral extends AnnotationLiteral<PlaceTyped> implements PlaceTyped { private final Class<? extends Place> value; public Class<? extends Place> value() { return value; } public PlaceTypedLiteral(Class<? extends Place> value) { this.value = value; } }
Example Bean Definition
@PlaceTyped(MyPlace.class) public class MyPlaceTokenizer implements PlaceTokenizer<MyPlace> { ...}
Programmatic Lookup of PlaceTokenizer for a given Place object (via .class)
@Inject @Any Instance<PlaceTokenizer<Place>> allPlaceTokenizers; ... //if place is instance of MyPlace the following should get MyPlaceTokenizer... allPlaceTokenizers.select(new PlaceTypedLiteral(place.getClass())).get();
The Good and Bad
This is easy (good), but its not type safe (bad)... I could very well have mixed Your and My place in the annotation and generic type, which would no doubt be a bug...
@PlaceTyped(YourPlace.class) public class MyPlaceTokenizer implements PlaceTokenizer<MyPlace> { ...}