2013-07-15 10 views
15

मैं अपना पहला एनोटेशन प्रोसेसर लिख रहा हूं और कुछ ऐसा लगता है जो तुच्छ लगता है लेकिन मुझे इसके बारे में कोई जानकारी नहीं मिल रही है।एनोटेशन प्रोसेसर में फ़ील्ड क्लास प्राप्त करें

मैं एक तत्व जब मैं इस संपत्ति मेरी प्रोसेसर में एक तत्व मैं किसी भी तरह से तत्व के प्रकार प्राप्त नहीं कर पा रहे के रूप में मिलता है मेरी एनोटेशन

@MyAnnotation String property; 

साथ एनोटेट है। इस मामले में एक स्ट्रिंग का प्रतिनिधित्व करने वाला क्लास या टाइप एलिमेंट उदाहरण प्राप्त करना चाहता है।

मैंने Class.forName() के साथ कंटेनर प्रकार की क्लास ऑब्जेक्ट को तुरंत चालू करने का प्रयास किया लेकिन यह क्लास नॉटफाउंड अपवाद को फेंक दिया। मुझे लगता है कि ऐसा इसलिए है क्योंकि मेरे पास कक्षा वाले वर्ग लोडर तक पहुंच नहीं है?

+0

आप 'Field.getType()' का उपयोग क्यों नहीं करते? – Desert

+1

क्योंकि मैं ओ मेरी टिप्पणियों में एक फील्ड उदाहरण के लिए पहुँच नहीं precessor जहाँ तक मुझे पता –

उत्तर

45

अपनी एनोटेशन प्रोसेसर चलाने पर, आपके पास संकलित कक्षाओं तक पहुंच नहीं है। एनोटेशन प्रसंस्करण का बिंदु यह है कि यह पूर्व संकलन होता है।

इसके बजाय, आपको एक एनोटेशन प्रोसेसर बनाना होगा जो विशेष रूप से आपके एनोटेशन प्रकार को संभालता है, फिर फ़ील्ड तक पहुंचने के लिए दर्पण API का उपयोग करें। उदाहरण के लिए:

@SupportedAnnotationTypes("com.example.MyAnnotation") 
public class CompileTimeAnnotationProcessor extends AbstractProcessor { 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, 
          RoundEnvironment roundEnv) { 
     // Only one annotation, so just use annotations.iterator().next(); 
     Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(
       annotations.iterator().next()); 
     Set<VariableElement> fields = ElementFilter.fieldsIn(elements); 
     for (VariableElement field : fields) { 
      TypeMirror fieldType = field.asType(); 
      String fullTypeClassName = fieldType.toString(); 
      // Validate fullTypeClassName 
     } 
     return true; 
    } 
} 

सत्यापन के लिए, आप अभी तक (उन है कि के बारे में टिप्पणी के साथ संकलित किया जा रहे हैं सहित) संकलित की MyType.class की तरह कुछ का उपयोग कर जो किसी भी कक्षाओं का उपयोग नहीं कर सकते हैं। इनके लिए, आपको तारों का उपयोग केवल करना होगा। ऐसा इसलिए है क्योंकि एनोटेशन प्रोसेसिंग प्री-कंपाइलिंग चरण के दौरान होती है जिसे "सोर्स पीढ़ी" कहा जाता है, जो कि संकलन का उपयोग करके कंपाइलर चलाने से पहले आपको स्रोत कोड उत्पन्न करने की अनुमति देता है।

एक उदाहरण सत्यापन सत्यापित करें कि फ़ील्ड प्रकार java.lang.String (जो पहले से ही संकलित किया गया है) है:

for (VariableElement field : fields) { 
    TypeMirror fieldType = field.asType(); 
    String fullTypeClassName = fieldType.toString(); 
    if (!String.class.getName().equals(fullTypeClassName)) { 
     processingEnv.getMessager().printMessage(
       Kind.ERROR, "Field type must be java.lang.String", field); 
    } 
} 

संसाधन

  • Main APT Page
  • Mirror API Javadocs (Java 7 and older)
  • संपादित करें:Mirror API Javadocs (Java 8)
    • ध्यान दें कि दर्पण API अब जावा 8 में javax.lang.model के तहत मानकीकृत है और पुरानी एपीआई बहिष्कृत है। अधिक जानकारी के लिए this blog post देखें। यदि आप javax कक्षाओं का उपयोग कर रहे हैं, तो आपको चिंता करने की आवश्यकता नहीं है।

संपादित करें:

मैं उस प्रकार पर भी टिप्पणियां प्राप्त करने के लिए फ़ील्ड प्रकार प्राप्त करना चाहते हैं। लेकिन ऐसा प्रतीत नहीं होता है कि यह संभव होगा?

वास्तव में यह संभव है!यह TypeMirror के बारे में अधिक तरीकों का उपयोग कर किया जा सकता है:

if (fieldType.getKind() != TypeKind.DECLARED) { 
    processingEnv.getMessager().printMessage(
      Kind.ERROR, "Field cannot be a generic type.", field); 
} 
DeclaredType declaredFieldType = (DeclaredType) fieldType; 
TypeElement fieldTypeElement = (TypeElement) declaredFieldType.asElement(); 

यहां से, आप दो विकल्प हैं:

  1. एनोटेशन आप खोजने की कोशिश कर रहे हैं पहले से ही संकलित किया गया है (अर्थात यह एक और पुस्तकालय से है) तो आप एनोटेशन प्राप्त करने के लिए सीधे कक्षा का संदर्भ दे सकते हैं।
  2. एनोटेशन आप खोजने की कोशिश कर रहे हैं संकलित नहीं किया है तो आप इसे AnnotationMirror उदाहरणों के माध्यम से संदर्भित कर सकते हैं (यानी यह है कि अपार्ट चल javac को वर्तमान कॉल में संकलित किया जा रहा है)।

पहले से ही,

DifferentAnnotation diffAnn = fieldTypeElement.getAnnotation(
     DifferentAnnotation.class); 
// Process diffAnn 

बहुत सीधी-सपाट संकलित इस आप एनोटेशन खुद के लिए सीधी पहुँच देता है।

संकलित नहीं

ध्यान दें कि यह समाधान एनोटेशन संकलित किया गया है या नहीं, की परवाह किए बिना काम करेंगे, यह सिर्फ ऊपर कोड के रूप में के रूप में साफ नहीं है।

private static <T> T findAnnotationValue(Element element, String annotationClass, 
     String valueName, Class<T> expectedType) { 
    T ret = null; 
    for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { 
     DeclaredType annotationType = annotationMirror.getAnnotationType(); 
     TypeElement annotationElement = (TypeElement) annotationType 
       .asElement(); 
     if (annotationElement.getQualifiedName().contentEquals(
       annotationClass)) { 
      ret = extractValue(annotationMirror, valueName, expectedType); 
      break; 
     } 
    } 
    return ret; 
} 

private static <T> T extractValue(AnnotationMirror annotationMirror, 
     String valueName, Class<T> expectedType) { 
    Map<ExecutableElement, AnnotationValue> elementValues = new HashMap<ExecutableElement, AnnotationValue>(
      annotationMirror.getElementValues()); 
    for (Entry<ExecutableElement, AnnotationValue> entry : elementValues 
      .entrySet()) { 
     if (entry.getKey().getSimpleName().contentEquals(valueName)) { 
      Object value = entry.getValue().getValue(); 
      return expectedType.cast(value); 
     } 
    } 
    return null; 
} 

मान लीजिए कि आप DifferentAnnotation एनोटेशन की तलाश कर रहे हैं और अपने स्रोत कोड की तरह दिखता है:

यहां कुछ तरीकों मैं एक बार लिखा था अपने वर्ग नाम से एक टिप्पणी के दर्पण से एक निश्चित मान प्राप्त करने के हैं इस:

@DifferentAnnotation(name = "My Class") 
public class MyClass { 

    @MyAnnotation 
    private String field; 

    // ... 
} 

इस कोड My Class प्रिंट होगा:

String diffAnnotationName = findAnnotationValue(fieldTypeElement, 
     "com.example.DifferentAnnotation", "name", String.class); 
System.out.println(diffAnnotationName); 
+0

के रूप में बहुत पूरी तरह से! धन्यवाद :) मैं कारण बताता हूं कि मैं यह क्यों चाहता था। मैं उस प्रकार के एनोटेशन प्राप्त करने के लिए फ़ील्ड प्रकार प्राप्त करना चाहता हूं। लेकिन ऐसा प्रतीत नहीं होता है कि यह संभव होगा? –

+0

@ EmilSjölander मेरे संपादन देखें – Brian

+0

बहुत बहुत धन्यवाद! बेहद अच्छी तरह लिखा है –

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