【发布时间】:2017-03-08 19:41:07
【问题描述】:
从this answer 开始,可以通过创建和安装新的内部AnnotationData 对象在运行时向Java 类添加注释。我很好奇Field 是否可行。似乎Field 处理注释的方式与Class 处理它们的方式大不相同。
我已经能够使用以下类成功地将注释添加到Field 类的declaredAnnotations 字段:
public class FieldRuntimeAnnotations {
private static final Field DECLARED_ANNOTATIONS_FIELD;
private static final Method DECLARED_ANNOTATIONS_METHOD;
static {
try {
DECLARED_ANNOTATIONS_METHOD = Field.class.getDeclaredMethod("declaredAnnotations");
DECLARED_ANNOTATIONS_METHOD.setAccessible(true);
DECLARED_ANNOTATIONS_FIELD = Field.class.getDeclaredField("declaredAnnotations");
DECLARED_ANNOTATIONS_FIELD.setAccessible(true);
} catch (NoSuchMethodException | NoSuchFieldException | ClassNotFoundException e) {
throw new IllegalStateException(e);
}
}
// Public access method
public static <T extends Annotation> void putAnnotationToField(Field f, Class<T> annotationClass, Map<String, Object> valuesMap) {
T annotationValues = TypeRuntimeAnnotations.annotationForMap(annotationClass, valuesMap);
try {
Object annotationData = DECLARED_ANNOTATIONS_METHOD.invoke(f);
// Get declared annotations
Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
(Map<Class<? extends Annotation>, Annotation>) DECLARED_ANNOTATIONS_FIELD.get(f);
// Essentially copy our original annotations to a new LinkedHashMap
Map<Class<? extends Annotation>, Annotation> newDeclaredAnnotations = new LinkedHashMap<>(declaredAnnotations);
newDeclaredAnnotations.put(annotationClass, annotationValues);
DECLARED_ANNOTATIONS_FIELD.set(f, newDeclaredAnnotations);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}
但是,该字段的声明类没有更新为正确的ReflectionData。所以基本上我需要用它的声明类“安装”新的字段信息,但我很难弄清楚如何。
为了更清楚我的要求,我的测试中的第三个断言失败了:
public class RuntimeAnnotationsTest {
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
public @interface TestAnnotation {}
public static class TestEntity {
private String test;
}
@Test
public void testPutAnnotationToField() throws NoSuchFieldException {
// Confirm class does not have annotation
TestAnnotation annotation = TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class);
Assert.assertNull(annotation);
Field f = TestEntity.class.getDeclaredField("test");
f.setAccessible(true);
FieldRuntimeAnnotations.putAnnotationToField(f, TestAnnotation.class, new HashMap<>());
// Make sure field annotation gets set
Assert.assertNotNull(f.getAnnotation(TestAnnotation.class));
// Make sure the class that contains that field is also updated -- THIS FAILS
Assert.assertNotNull(TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class));
}
}
我知道我想要达到的目标相当荒谬,但我很享受这个练习 :D ... 有什么想法吗?
【问题讨论】:
标签: java reflection