67

Java アノテーション マジックを実行しようとしています。私はまだ注釈のトリックに追いついていると言わざるを得ず、特定のことはまだ私にははっきりしていません.

だから...私はいくつかの注釈付きのクラス、メソッド、およびフィールドを持っています。リフレクションを使用してクラスでいくつかのチェックを実行し、いくつかの値をクラスに注入するメソッドがあります。これはすべてうまくいきます。

ただし、現在、注釈のインスタンス (いわば) が必要な場合に直面しています。つまり...注釈は通常のインターフェースとは異なり、クラスの匿名実装を行うことはできません。わかった。ここで同様の問題に関するいくつかの投稿を見てきましたが、探しているものに対する答えが見つからないようです。

私は基本的に、注釈のインスタンスを取得して、リフレクションを使用してそのフィールドの一部を設定できるようにしたいと考えています(私は思います)。これを行う方法はありますか?

4

10 に答える 10

90

まあ、それほど複雑なことではないようです。本当!

同僚が指摘したように、次のように (任意のインターフェイスと同様に) 注釈の匿名インスタンスを簡単に作成できます。

マイアノテーション:

public @interface MyAnnotation
{

    String foo();

}

呼び出しコード:

class MyApp
{
    MyAnnotation getInstanceOfAnnotation(final String foo)
    {
        MyAnnotation annotation = new MyAnnotation()
        {
            @Override
            public String foo()
            {
                return foo;
            }

            @Override
            public Class<? extends Annotation> annotationType()
            {
                return MyAnnotation.class;
            }
        };

        return annotation;
    }
}

マーティン・グリゴロフの功績。

于 2013-04-30T14:59:46.893 に答える
9

Hibernate Validator プロジェクトのこのような注釈プロキシを使用できます(免責事項: 私はこのプロジェクトのコミッターです)。

于 2013-05-01T20:58:02.960 に答える
7

使用できますsun.reflect.annotation.AnnotationParser.annotationForMap(Class, Map)

public @interface MyAnnotation {
    String foo();
}

public class MyApp {
    public MyAnnotation getInstanceOfAnnotation(final String foo) {
        MyAnnotation annotation = AnnotationParser.annotationForMap(
            MyAnnotation.class, Collections.singletonMap("foo", "myFooResult"));
    }
}

欠点: のクラスsun.*は後のバージョンで変更される可能性があり (ただし、このメソッドは同じシグネチャを持つ Java 5 以降存在します)、すべての Java 実装で使用できるわけではありません。このディスカッションを参照してください。

それが問題である場合: 独自の汎用プロキシを作成できます。InvocationHandlerこれは、まさにAnnotationParser内部で行われていることです。または、ここMyAnnotationで定義されている独自の実装を使用します。どちらの場合も、を実装することを忘れないでください。その結果は、 のために特別に文書化されています。annotationType()equals()hashCode()java.lang.Annotation

于 2016-08-08T13:19:05.393 に答える
1

Apache Commons AnnotationUtilsの助けを借りてプロキシ アプローチを使用するかなり大雑把な方法

public static <A extends Annotation> A mockAnnotation(Class<A> annotationClass, Map<String, Object> properties) {
    return (A) Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class<?>[] { annotationClass }, (proxy, method, args) -> {
        Annotation annotation = (Annotation) proxy;
        String methodName = method.getName();

        switch (methodName) {
            case "toString":
                return AnnotationUtils.toString(annotation);
            case "hashCode":
                return AnnotationUtils.hashCode(annotation);
            case "equals":
                return AnnotationUtils.equals(annotation, (Annotation) args[0]);
            case "annotationType":
                return annotationClass;
            default:
                if (!properties.containsKey(methodName)) {
                    throw new NoSuchMethodException(String.format("Missing value for mocked annotation property '%s'. Pass the correct value in the 'properties' parameter", methodName));
                }
                return properties.get(methodName);
        }
    });
}

渡されたプロパティの型は、注釈インターフェイスで宣言された実際の型でチェックされず、欠落している値は実行時にのみ検出されます。

Tobias Liefke の回答のように内部 Java API を使用することの欠点がなく、kaqqao の回答(およびおそらくGunnar の回答) で言及されているコードと機能がかなり似ています。

于 2019-08-06T10:00:08.083 に答える