2013-07-15 8 views
15

私は最初のアノテーションプロセッサーを作成していて、些細なことに問題を抱えていますが、それに関する情報が見つかりません。アノテーションのフィールドクラスを取得するプロセッサー

私は私がどのような方法で要素の型を取得するように見えることができない私のプロセッサ内の要素として、このプロパティを取得すると、私の注釈

@MyAnnotation String property; 

と注釈付き要素を持っています。この場合、Stringは、Stringを表すClassまたはTypeElementインスタンスを取得します。

Class.forName()でコンテナタイプのクラスオブジェクトをインスタンス化しようとしましたが、ClassNotFoundExceptionがスローされました。これは、クラスを含むクラスローダーにアクセスできないためだと思いますか?

+0

'Field.getType()'を使わないのはなぜですか? – Desert

+1

私は私の知る限り私の注釈のプリセッサのフィールドインスタンスにアクセスできないので、 –

答えて

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); 
    } 
} 

リソース

編集:

私はそのタイプの注釈を取得するには、フィールドの種類を取得したいです。しかし、これは可能なようには思われませんか?

確かに可能です!これは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(); 

ここから、次の2つの選択肢があります:あなたが見つけるためにしようとしている注釈がすでにコンパイルされている場合は(

  1. をすなわち、それが別のライブラリからです)、クラスを直接参照してアノテーションを取得することができます。
  2. 検索しようとしている注釈がコンパイルされていない(つまり、APTを実行しているjavacの現在の呼び出しでコンパイルされている)場合は、AnnotationMirrorインスタンスで参照できます。

が既に

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

ありがとう!非常によく書かれた –

関連する問題