the travails of method getAnnotation in class Declaration (apt programming)
well the problem is at least documented:
you are in trouble if you want to read a value of an annotation which happens to be a class !
I can vaguely understand the reason....
but now what do I do if I need to get such a value?
different hacks spring to my mind:
- get the name of the Class value as a String and perform a Class.forName
- build a Map <TypeMirror, Class> and try to get the TypeMirror trough inspection of results of getAnnotationMirrors() ...
which hack is the least ugly?
or may be other more elegant options?
urgent thanks!
[610 byte] By [
amadea] at [2007-10-2 6:36:52]

continued....
May I suggest the APT developpers to provide something like a static method like
EnumValues.valueAsString(enumInstance, enumfieldName)
thus when requesting a value which is an instance of Class
we could at least easily retrieve its name
then it would be to the programmer's responsability to be aware
wether an instance of this Class could be requested at compile time..
makes sense?
amadea at 2007-7-16 13:39:26 >

Why?
In apt, you are using the mirror API which is similar to but also quite different from reflection.
Some say that a mirror is where you look for a reflection, which sounds pretty neat, but doesn't really help the likes of you understand things.
For a number of reasons, the mirror API is just modelling source and class files, and NOT modelling the classes loaded into the JVM that is running the apt tool.
One reason, is that the class file might not yet exist because APT hasn't actually compiled it yet.
But understanding why you can't do something how you'd expect to is all very consoling and such, but still doesn't help. You want some code, right?
How
What I generally do is call that nice convenient method that returns actual values, but throws an exception when the value is a class, then look in the exception for the Declaration, then check its name.
Here's a block of code (from rapt project on java.net) that does what (I suspect) you want.protected ClassDeclaration getValue(Declaration d) {
RenamableImplementation at =
d.getAnnotation(RenamableImplementation.class);
try {
at.value();
} catch (MirroredTypeException mte) {
TypeMirror v = mte.getTypeMirror();
if(! (v instanceof ClassType) ) {
error(d,
"@RenamableImplementation(%s.class), %s is not a class",
v,v);
return null;
}
return ((ClassType)v).getDeclaration();
}
return null;
}
error is just a varargs convenience wrapper for the Messager.printError() method.void error(Declaration where, String format, Object... args) {
env.getMessager().printError(where.getPosition(),
String.format(format,args)
);
}
Rant
That exception thing is a bit of a kludge, but its quite a nice kludge that maintains the distinction between the mirror API and the reflection API. In a way, it would have been better if the JSR-175 (annotations) expert group had defined class annotation elements to have a type of java.lang.reflect.Type.
The annotation method would have returned Class<?> at runtime, but APT's DeclaredType could have also implemented the java.lang.reflect.Type interface and the annotation could have returned a DeclaredType. Everything would have worked nicely I suspect, but nobody foresaw the problems and now we are stuck with annotations defined with a runtime Class rather than an interface. Actually maybe they foresaw other problems with doing it this way.
Everyone is at fault, because everyone could have looked at the 175 spec at the review stages and done something about it. Nobody did.
> Why?
>
> In apt, you are using the mirror API which is similar
> to but also quite different from reflection.
>
> Some say that a mirror is where you look for a
> reflection, which sounds pretty neat, but doesn't
> really help the likes of you understand things.
For more understanding of general issues in designing reflective APIs, read
Gilad Bracha and David Ungar. Mirrors: Design Principles for Meta-level Facilities of Object-Oriented Programming Languages. In Proc. of the ACM Conf. on Object-Oriented Programming, Systems, Languages and Applications, October 2004.
http://www.bracha.org/mirrors.pdf
what I did (under pressure) is this:
since the classes I needed were supposed to be there at compile time
I replaced the values of annotation by Enumerated constants of a type that could yield a class instance;
this works finely (though not a general solution) and By The Way this led me to think about the notion of "symbolic reference" implemented by Enum types: though at first glance one would think that using an enumerated type in that case introduces more coupling between classes actually the reverse is true!
amadea at 2007-7-16 13:39:26 >

Amade,
That is a good solution provided you know ALL the possible values for the annotation. Enums are not extendable, A user cannot add additional values to an enum by any mechanism other than modifying the enum declaration. Using an enum allows the annotation to declare the functionality it wants (the enum names the functionality), rather than specifying which class implements that functionality.
If you have the class files of the valid values available to your processor, then catching the MirroredTypeException will also work fine, and you can use a bounded wildcard on the annotation member type thusClass<? extends Number> value();
Also I think it is better not to make an API's interface suboptimal merely to make the implementation easier. You seem to be adding an enum into your API just so you don't have to catch the MirroredTypeException.
I guess it comes down to whether the values really are from a known finite set (an enum) or whether they need to be extensible.
I'll file your solution away in case I have situations where it is applicable.
Bruce
sorry late to respond (I was out for some time)
I started to use enums in a very special way: classes of a config package that is open to code modifications.
though not universal it is very useful: in that way the code is "extensible" (well not really like inehritance and so on... but it is ok).
since the exception catching is a kludge I suggest again to set up an appropriate method.
thanks
amadea at 2007-7-16 13:39:26 >
