2010-06-21 15 views
5

Bir ek açıklamadaki bir ek açıklamanın değerini bir ek açıklama işlemcisi ve ek açıklama aynası kullanarak okumaya çalışıyorum, ancak geri dönüyorum. Bunun bir Enum'u bir VariableElement olarak sarmalayan AnnotationValue ile ilgisi olduğunu düşünüyorum. VariableElement # getConstantValue() belgesine göre "Bu değişken, derleme zamanı sabiti için başlatılan son bir alan ise, değerini döndürür." Tamam, ama final bir açıklama notu için geçerli bir değiştirici değil. Ayrıca not, diğer ek açıklama değerlerini okumada hiç sorunum yok, sadece Enums.Ek Açıklama İşlemcisindeki AnnotationValue öğesinden bir Enum nasıl yakalanır

AnnotationValue, çalışma zamanında bir Symbol.VarSymbol olarak gösteriliyor gibi görünüyor. Ancak Symbol.VarSymbol # getConstantValue() öğesi yalnızca nesneyi döndürmesi gerektiği gibi görünüyor.

Son olarak, AnnotationValue öğesinde toString() yaparsam uygun değeri alırım.

Ek Açıklama:

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

    public static enum Behavior 
    { 
     NEW, NULL; 
    } 
} 

benim İşlemci kısmı ve döngüler bir bolluk içine yuvalanmış uygun AnnotaionMirror ulaşmak için:

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: İşlemci daha eksiksiz bir sürümünü. getConstantValue belgelerine itibaren

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

Bu ek açıklama işleminin Java SE 6 sürümünden bahsetmeyi unuttum. –

cevap

3

.

Özellikle

", enum sabitleri derlemek zamanlı sabitleri olarak kabul edilmez sabit bir değer olması için, bir alanın tip basit bir tür ya olmalıdır veya Dize. "

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

enum değeri sabit olsun ya getAnnotation API'sini ya da bir AnnotationValueVisitor kullanın.

+0

Bu tuhaflık, o sıralar VariableElement'e yerleştirildi; from AnnotationValue: "VariableElement (bir enum sabitini temsil eder)" Neyse AnnotationValueVisitor'da detaylandırır mısınız? özel sınıfı AnnotationValueVisitorImpl SimpleAnnotationValueVisitor6 { @Override korunan nesne DEFAULTACTION (Nesne o, nesne p) {\t dönüş o uzanmaktadır: Aşağıdaki çalıştı \t} } Ancak AnnotationValue'nin kabul yöntemine ilettiğimde, aradığım enum değil Symbol.VarSymbol alıyorum. –

+0

FYI @ joe-darcy Java Eknotation API'sini yazdı –

1

Sizinkiyle benzer bir sorun yaşadım (enumlarla uğraşmadığım için, String olmayan/ilkel olmayan sabit değere ihtiyacım vardı) ve kaynak koduna Compiler Tree API aracılığıyla erişerek çözdüm. Senin AbstractProcessor yılında

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. init yöntemini geçersiz kılarak cari derleme ağacının bir başvuru kaydedin:

1. Özel bir TreePathScanner oluşturun:

İşte genel tarifi:

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

// 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(); 

Ve işte bu kadar: 0 3. (sizin durumunuzda bir enum) VariableElement için başlatma kaynak kodu alın! Bununla birlikte, açıklamalı bir alan için, normalde VariableElement.getContantValue (yani, bir String veya ilkel olmayan herhangi bir "sabit") kullanamayacağınız başlatma değerine ulaşabilmeniz gerekir.

Daha fazla bilgi ve örnek için bu article: Source Code Analysis Using Java 6 APIs numaralı telefonu okuyun.

İlgili konular