63

クラスがあると想像してください:

@Something(someProperty = "some value")
public class Foobar {
    //...
}

これはすでにコンパイルされており(ソースを制御できません)、jvmの起動時にクラスパスの一部です。実行時に「何らかの値」を別のものに変更できるようにしたいと考えています。これにより、その後のリフレクションはデフォルトの「何らかの値」ではなく新しい値になります。

これは可能ですか?もしそうなら、どのように?

4

7 に答える 7

43

このコードは、多かれ少なかれあなたが求めることを行います - それは概念の簡単な証明です:

  • 適切な実装では、declaredAnnotations
  • Class.java のアノテーションの実装が変更されると、コードが壊れます (つまり、将来いつでも壊れる可能性があります)。
  • 副作用があるかどうかはわかりません...

出力:

oldAnnotation = 何らかの値
modifiedAnnotation = 別の値

public static void main(String[] args) throws Exception {
    final Something oldAnnotation = (Something) Foobar.class.getAnnotations()[0];
    System.out.println("oldAnnotation = " + oldAnnotation.someProperty());
    Annotation newAnnotation = new Something() {

        @Override
        public String someProperty() {
            return "another value";
        }

        @Override
        public Class<? extends Annotation> annotationType() {
            return oldAnnotation.annotationType();
        }
    };
    Field field = Class.class.getDeclaredField("annotations");
    field.setAccessible(true);
    Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) field.get(Foobar.class);
    annotations.put(Something.class, newAnnotation);

    Something modifiedAnnotation = (Something) Foobar.class.getAnnotations()[0];
    System.out.println("modifiedAnnotation = " + modifiedAnnotation.someProperty());
}

@Something(someProperty = "some value")
public static class Foobar {
}

@Retention(RetentionPolicy.RUNTIME)
@interface Something {

    String someProperty();
}
于 2013-01-11T10:35:05.317 に答える
3

これは Java 8 を搭載した私のマシンで動作します。ignoreUnknown注釈の値をtrue@JsonIgnoreProperties(ignoreUnknown = true)からfalseに変更します。

final List<Annotation> matchedAnnotation = Arrays.stream(SomeClass.class.getAnnotations()).filter(annotation -> annotation.annotationType().equals(JsonIgnoreProperties.class)).collect(Collectors.toList());    

final Annotation modifiedAnnotation = new JsonIgnoreProperties() {
    @Override public Class<? extends Annotation> annotationType() {
        return matchedAnnotation.get(0).annotationType();
    }    @Override public String[] value() {
        return new String[0];
    }    @Override public boolean ignoreUnknown() {
        return false;
    }    @Override public boolean allowGetters() {
        return false;
    }    @Override public boolean allowSetters() {
        return false;
    }
};    

final Method method = Class.class.getDeclaredMethod("getDeclaredAnnotationMap", null);
method.setAccessible(true);
final Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) method.invoke(SomeClass.class, null);
annotations.put(JsonIgnoreProperties.class, modifiedAnnotation);
于 2016-10-28T07:34:07.233 に答える
1

Java 8 でこのソリューションを試してください

public static void main(String[] args) throws Exception {
    final Something oldAnnotation = (Something) Foobar.class.getAnnotations()[0];
    System.out.println("oldAnnotation = " + oldAnnotation.someProperty());
    Annotation newAnnotation = new Something() {

        @Override
        public String someProperty() {
            return "another value";
        }

        @Override
        public Class<? extends Annotation> annotationType() {
            return oldAnnotation.annotationType();
        }
    };
    Method method = Class.class.getDeclaredMethod("annotationData", null);
    method.setAccessible(true);
    Object annotationData = method.invoke(getClass(), null);
    Field declaredAnnotations = annotationData.getClass().getDeclaredField("declaredAnnotations");
    declaredAnnotations.setAccessible(true);
    Map<Class<? extends Annotation>, Annotation> annotations = (Map<Class<? extends Annotation>, Annotation>) declaredAnnotations.get(annotationData);
    annotations.put(Something.class, newAnnotation);

    Something modifiedAnnotation = (Something) Foobar.class.getAnnotations()[0];
    System.out.println("modifiedAnnotation = " + modifiedAnnotation.someProperty());
}

@Something(someProperty = "some value")
public static class Foobar {
}

@Retention(RetentionPolicy.RUNTIME)
@interface Something {
    String someProperty();
}
于 2016-10-15T12:42:40.110 に答える
-4

アノテーション属性値は定数である必要があります-したがって、深刻なバイトコード操作を実行したい場合を除いて、それは不可能です。必要なアノテーションを使用してラッパークラスを作成するなど、よりクリーンな方法はありますか?

于 2013-01-10T23:14:21.410 に答える