56

wiki ドキュメントの自動生成に使用する @Pojo というカスタム アノテーションがあります。

package com.example.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Pojo {
    Class<?> value();
}

私はこのように使用します:

@Pojo(com.example.restserver.model.appointment.Appointment.class)

リソースメソッドにアノテーションを付けて、アノテーションプロセッサが期待するリソースとタイプを説明するwikiページを自動的に生成できるようにします。

value注釈プロセッサでフィールドの値を読み取る必要がありますが、実行時エラーが発生します。

私のプロセッサのソースコードには、次の行があります。

final Pojo pojo = element.getAnnotation(Pojo.class);
// ...
final Class<?> pojoJavaClass = pojo.value();

しかし、プロセッサは実際のクラスを利用できません。javax.lang.model.type.TypeMirror代わりに、実際のクラスの代理として aが必要だと思います。入手方法がわかりません。

私が得ているエラーは次のとおりです。

javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror com.example.restserver.model.appointment.Appointment

これは、私の注釈Appointmentの 1 つで言及されているクラスです。@Pojo

残念ながら、Java アノテーション処理に関するドキュメントやチュートリアルはほとんどないようです。ググってみた。

4

4 に答える 4

53

私はまったく同じ質問をするためにここに来ました。...そしてラルフによって投稿された同じブログリンクを見つけました。

長い記事ですが、とても豊富です。ストーリーの要約-それを行うには、簡単な方法と「より正しい」方法の2つの方法があります。

これは簡単な方法です。

private static TypeMirror getMyValue1(MyAnnotation annotation) {
    try
    {
        annotation.myValue(); // this should throw
    }
    catch( MirroredTypeException mte )
    {
        return mte.getTypeMirror();
    }
    return null; // can this ever happen ??
}

他のより退屈な方法(例外なし):

private static AnnotationMirror getAnnotationMirror(TypeElement typeElement, Class<?> clazz) {
    String clazzName = clazz.getName();
    for(AnnotationMirror m : typeElement.getAnnotationMirrors()) {
        if(m.getAnnotationType().toString().equals(clazzName)) {
            return m;
        }
    }
    return null;
}

private static AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String key) {
    for(Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : annotationMirror.getElementValues().entrySet() ) {
        if(entry.getKey().getSimpleName().toString().equals(key)) {
            return entry.getValue();
        }
    }
    return null;
}


public TypeMirror getMyValue2(TypeElement foo) {
    AnnotationMirror am = getAnnotationMirror(foo, MyAnnotation.class);
    if(am == null) {
        return null;
    }
    AnnotationValue av = getAnnotationValue(am, "myValue");
    if(av == null) {
        return null;
    } else {
        return (TypeMirror)av.getValue();
    }
}

もちろん、TypeMirrorを取得すると、(少なくとも私の経験では)ほとんどの場合、代わりにTypeElementが必要になります。

private TypeElement asTypeElement(TypeMirror typeMirror) {
    Types TypeUtils = this.processingEnv.getTypeUtils();
    return (TypeElement)TypeUtils.asElement(typeMirror);
}

...その最後の少しの非自明なビットは、私が最初にそれを整理する前に私に1時間の髪の毛を引っ張るのにかかりました。これらの注釈プロセッサは、実際にはそれほど難しくはありません。APIは最初は非常に混乱し、非常に冗長です。すべての基本的な操作を明確にするヘルパークラスを出したいと思っています...しかし、それは別の日の話です(必要に応じて私にメッセージを送ってください)。

于 2012-04-16T00:56:27.197 に答える
31

この記事を読んだことがありますか:http://blog.retep.org/2009/02/13/getting-class-values-from-annotations-in-an-annotationprocessor/

そこでの秘訣は、実際にgetAnnotation()を使用して、MirroredTypeExceptionをキャッチすることです。驚いたことに、例外は必要なクラスのTypeMirrorを提供します。

これが良い解決策かどうかはわかりませんが、それは1つです。私の個人的な意見では、MirroredTypeの背後にあるタイプを取得しようとしますが、これが可能かどうかはわかりません。

于 2011-10-07T13:35:03.050 に答える
1

これは私のトリックです:

public class APUtils {

  @FunctionalInterface
  public interface GetClassValue {
    void execute() throws MirroredTypeException, MirroredTypesException;
  }

  public static List<? extends TypeMirror> getTypeMirrorFromAnnotationValue(GetClassValue c) {
    try {
      c.execute();
    }
    catch(MirroredTypesException ex) {
      return ex.getTypeMirrors();
    }
    return null;
  }

}

次に、任意の Annotation 値で使用できます。

public @interface MyAnnotationType {
  public Class<?>[] value() default {};
}

@MyAnnotationType(String.class)
public class Test { ... }

注釈プロセッサでの使用

MyAnnotationType a = element.getAnnotation(MyAnnotationType.class);
List<? extends TypeMirror> types = APUtils.getTypeMirrorFromAnnotationValue(() -> a.value());

JDK 1.8.0_192 でテスト済み

于 2018-10-13T14:15:11.090 に答える