2010-06-21 20 views
5

में एनोटेशन वैल्यू से एनम कैप्चर कैसे करें मैं एनोटेशन प्रोसेसर और एनोटेशन मिरर का उपयोग करके एनोटेशन में एनम के मूल्य को पढ़ने की कोशिश कर रहा हूं, लेकिन मैं वापस शून्य हो रहा हूं। मुझे लगता है कि इसे एनोटेशन वैल्यू के साथ एक वैरिएबल एलिमेंट के रूप में एक एनम लपेटना होगा। VariableElement # getConstantValue() के लिए दस्तावेज़ कहते हैं, "इस चर के मान को वापस कर देता है यदि यह एक अंतिम फ़ील्ड है जो संकलन-समय निरंतर प्रारंभ होता है।" ठीक है, लेकिन अंतिम एनोटेशन सदस्य के लिए वैध संशोधक नहीं है। यह भी ध्यान में है कि मुझे अन्य एनोटेशन मूल्यों को पढ़ने में कोई परेशानी नहीं है, केवल Enums।एनोटेशन प्रोसेसर

मैं कुछ sleuthing किया है एक ऐसा लगता है AnnotationValue रन-टाइम में एक Symbol.VarSymbol के रूप में instantiated है, लेकिन Symbol.VarSymbol # getConstantValue() लगता है कि यह सिर्फ ऑब्जेक्ट प्रदान।

अंत में यदि मैं एनोटेशन वैल्यू पर टॉस्ट्रिंग() करता हूं तो मुझे उचित मूल्य मिलता है।

एनोटेशन:

package annotation; 
public @interface AnAnnotation 
{ 
    String value(); 
    Behavior defaultBehavior() default Behavior.NEW; 

    public static enum Behavior 
    { 
     NEW, NULL; 
    } 
} 

मेरी प्रोसेसर का एक हिस्सा और छोरों की अधिकता के अंदर नेस्टेड उचित 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 + ""); 

    } 
    ... 
} 

संपादित करें: प्रोसेसर का एक और अधिक पूर्ण संस्करण।

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; 
    } 
} 
+0

मैं उल्लेख करना भूल गया कि यह एनोटेशन प्रोसेसिंग का जावा एसई 6 संस्करण है। –

उत्तर

3

getConstantValue के लिए दस्तावेज़ से:।

"विशेष रूप से, enum स्थिरांक संकलन समय स्थिरांक माना नहीं कर रहे हैं एक निरंतर मूल्य करवाने के लिए, एक फ़ील्ड के प्रकार या तो एक आदिम प्रकार होना चाहिए या स्ट्रिंग। "

http://java.sun.com/javase/6/docs/api/javax/lang/model/element/VariableElement.html#getConstantValue()

enum का मूल्य लगातार मिल या तो getAnnotation एपीआई का उपयोग या एक AnnotationValueVisitor का उपयोग करें।

+0

यह अजीब बात है कि enums को VariableElement में रखा गया है; एनोटेशन वैल्यू से: "वैरिएबल एलिमेंट (एनम निरंतर प्रतिनिधित्व)" वैसे भी आप एनोटेशनवेल्यूविजिटर पर विस्तार कर सकते हैं? मैंने कोशिश की है: निजी वर्ग AnnotationValueVisitorImpl फैली SimpleAnnotationValueVisitor6 <वस्तु, वस्तु> { @Override संरक्षित वस्तु defaultAction (वस्तु ओ, वस्तु पी) {\t वापसी ओ; \t} } हालांकि जब मैं इसे एनोटेशन वैल्यू की स्वीकृति विधि में पास करता हूं तो मुझे एक प्रतीक मिलता है। वर्सिम्बोल और मैं जिस enum की तलाश में था। –

+0

एफवाईआई @ जो-डार्सी ने जावा एनोटेशन एपीआई लिखा –

1

मुझे आपकी एक ही समस्या थी (सिवाय इसके कि मैं enums से निपट नहीं रहा था, मुझे एक गैर स्ट्रिंग/गैर-आदिम स्थिरांक के मूल्य की आवश्यकता थी) और इसे Compiler Tree API के माध्यम से स्रोत कोड तक पहुंचकर हल किया गया।

1. एक कस्टम TreePathScanner बनाएँ::

private static class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> { 

private String fieldName; 

private String fieldInitializer; 

public void setFieldName(String fieldName) { 
    this.fieldName = fieldName; 
} 

public String getFieldInitializer() { 
    return this.fieldInitializer; 
} 

@Override 
public Object visitVariable(VariableTree variableTree, Trees trees) { 
    if (variableTree.getName().toString().equals(this.fieldName)) { 
     this.fieldInitializer = variableTree.getInitializer().toString(); 
    } 

    return super.visitVariable(variableTree, trees); 
} 

2. अपने AbstractProcessor में, init विधि अधिभावी द्वारा वर्तमान संकलन पेड़ के लिए एक संदर्भ बचाने

यहाँ सामान्य नुस्खा है:

@Override 
public void init(ProcessingEnvironment pe) { 
    super.init(pe); 
    this.trees = Trees.instance(pe); 
} 

3. VariableElement (आपके मामले में एक enum) के लिए प्रारंभ स्रोत कोड प्राप्त करें:

// assuming theClass is a javax.lang.model.element.Element reference 
// assuming theField is a javax.lang.model.element.VariableElement reference 
String fieldName = theField.getSimpleName().toString(); 
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner(); 
TreePath tp = this.trees.getPath(theClass); 

codeScanner.setFieldName(fieldName); 
codeScanner.scan(tp, this.trees); 
String fieldInitializer = codeScanner.getFieldInitializer(); 

और बस हो गया! इसके साथ आप एक एनोटेटेड फ़ील्ड के लिए प्रारंभिक मान प्राप्त करने में सक्षम होना चाहिए, कि आप आमतौर पर VariableElement.getContantValue (यानी कोई भी "स्थिर" का उपयोग नहीं कर सकते जो स्ट्रिंग या आदिम नहीं है)।

अधिक पढ़ने और उदाहरणों के लिए यह article: Source Code Analysis Using Java 6 APIs पढ़ें।

संबंधित मुद्दे