0
從this answer可以通過創建和安裝新的內部對象AnnotationData
在運行時向Java類添加註釋。我很好奇Field
是否可能。看起來Field
處理註釋的方式與Class
處理註釋的方式有很大不同。使用Java反射API在運行時修改字段的聲明註釋
我已經能夠註釋成功添加到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 ...有什麼想法?
工程就像一個魅力!我錯過了調用'Class.class'方法'privateGetDeclaredFields'的關鍵部分,該方法聲明瞭帶有布爾型參數'false'的類。謝謝! – heez