if that example is working then I missed out part of your change. Before your patch, if you asked the ClassNode of Integer for the FieldNode MAX_VALUE, you got no initialExpression, so you could not get an constant expression and no value to use... right, I missed out this part:
try {
if (type.isResolved()) {
Field field = type.getTypeClass().getField(pe.getPropertyAsString());
if (field != null) {
return new ConstantExpression(field.get(null));
}
}
} catch(Exception e) {/*ignore*/}
If the class has an static initializer, then this code here will cause the static initializer to be executed, else it is impossible to get the value. And I thought we don't want this to happen. Btw, this part of the code forgets to check that the field is static, but you swallow the exception anyway... which is another part I don't like. If we execute the static initializer, then why making things even worse by swallowing any exception that initializer may throw? Then I don't understand your text about interfaces. Normal interfaces are not that much different from normal classes. They have an static initializer too, and that one will get executed as well. Only in case of an annotation it is possible to read the value directly without first executing the static initializer.
Also it is a bit unclear to me why most of your code is in StaticImportVisitor. If I got it right, then you transform ClassNode.Field variant used by a PropertyExpression, even if that is outside of an annotation. If we are going to add such dangerous code, that executes static initializers, then we should not make matters worse and execute it for parts we don't even need... that is unless I misread the code and it is really limited to annotations... If it is limited to annotations, then it should be in an annotations handling visitor or a new visitor. It is no good to just enlarge the existing visitors, especially not the big ones. Your argument that you cannot do it in ExtendedVerifier is one I cannot follow. Sure, there the values are pulled out, but what is so bad for this? Why not change AnnotationVisitor to do exactly that? It is not like the constant will have any value for us in other parts at the moment.
As for precompiled Groovy classes. I don't folow that argument. The code you added will execute the static initializer, thus it will not make any difference between precompiled Groovy code or Java code, regardless of being a class or interface. The only case we can safely support is groovy code we currently compile, which is too limited.
Can I think of a better approach that works in all cases? No. We could try reading the class in bytecode and extract this information from there, but that is lot more complicated and will not work if we don't have the bytecode.. which at runtime is a common case.
As per http://www.nabble.com/Annotation-values-in-Groovy.-td20824889.html and looking at the code, it looks like annotation values in groovy can only be constant values (like Strings, classes, numbers, other annotations and enums, etc).
In this case, annotation value itself is a property expression PersonDao.DAO_ID, which is pointing to a static final String but in terms of groovy internals, it is not a constant expression but a property expression.
So, should this case be seen as a defect or as designed?