I am trying to read the value of an enum in an annotation using an annotation processor and annotation mirror, but I am getting back null. I think this has to do with the AnnotationValue wrapping an Enum as a VariableElement. The doc for VariableElement#getConstantValue() says "Returns the value of this variable if this is a final field initialized to a compile-time constant." Okay, but final isn't a valid modifier for an annotation member. Also of note is I have no trouble reading other annotation values, just Enums.
I've done some sleuthing an it appears the AnnotationValue is instantiated as a Symbol.VarSymbol at run-time, but Symbol.VarSymbol#getConstantValue() looks like it should just return the object.
Finally if I do a toString() on the AnnotationValue I get the proper value.
The Annotation:
package annotation;
public @interface AnAnnotation
{
String value();
Behavior defaultBehavior() default Behavior.NEW;
public static enum Behavior
{
NEW, NULL;
}
}
Part of my Processor and nested inside a plethora of loops to get at the proper AnnotaionMirror:
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues = elemUtils.getElementValuesWithDefaults(annotationMirror);
for (ExecutableElement method : annotationValues.keySet())
{
...
else if ("defaultBehavior".equals(method.getSimpleName().toString()))
{
defaultBehavior = (Behavior)( (VariableElement)annotationValues.get(method).getValue()).getConstantValue();
// This prints "NEW" or "NULL" correctly
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,annotationValues.get(method).toString());
// This prints null incorrectly (expect "NEW" or "NULL")
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, defaultBehavior + "");
}
...
}
EDIT: a more complete version of the Processor.
package annotation.processor;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import javax.tools.*;
import annotation.AnAnnotation;
import annotation.AnAnnotation.Behavior;
@SupportedAnnotationTypes("annotation.AnAnnotation")
public class AnAnnotationProcessor extends AbstractProcessor
{
Types typeUtils;
Elements elemUtils;
@Override
public void init(ProcessingEnvironment processingEnv)
{
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
elemUtils = processingEnv.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv)
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"Entering AnnotationNullableClassProcessor");
/****** Iterate over all annotaions being processed (only AnAnnotation) ******/
for (TypeElement annotation : annotations)
{
/****** Iterate over all elements that are annotated with the annotation ******/
for (Element element : roundEnv.getElementsAnnotatedWith(annotation))
{
/****** Iterate over all the declared annotations of the element ******/
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors())
{
final String annotationTypeName = annotationMirror.getAnnotationType().toString();
// Process annotations of type AnAnnotation
if (annotationTypeName.equals(AnAnnotation.class.getName()))
{
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues = elemUtils.getElementValuesWithDefaults(annotationMirror);
/****** Iterate over the annotation's values. ******/
for (ExecutableElement method : accessorValues.keySet())
{
if ("defaultBehavior".equals(method.getSimpleName().toString()))
{
Behavior defaultBehavior = (Behavior)( (VariableElement)annotationValues.get(method).getValue()).getConstantValue();
// This prints "NEW" or "NULL" correctly
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,annotationValues.get(method).toString());
// This prints null incorrectly (expect "NEW" or "NULL")
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, defaultBehavior + "");
}
}
}
}
}
}
return true;
}
}