猿问

递归修改用给定注释注释的对象中的所有字段

给定一个输入对象,我需要使用给定的注释查找其中的所有字段,并使用某个值对其进行修改。


该注释也可以存在于给定输入对象内的对象中。


public class A {

  private B b;


  @MyAnnotation

  private String s;


}


public class B {


    @MyAnnotation

    private String a;


    private String b;

}

在这种情况下,输出应该是字段 s 和 a,我需要用一些字符串修改相同的内容。我从 apache 中找到了 fieldUtils,它给出了给定类的注释,我想我可以添加一个简单的 DFS 搜索来查找具有给定注释的所有字段。使用反射设置值时出现问题,我需要将对象指定为field.set(). 我不确定在设置 a 的值时应该使用哪个对象以及如何以通用方式获取它(以防我需要在此示例中检索BfromA的实例)


ITMISS
浏览 267回答 3
3回答

慕尼黑8549860

要递归修改用给定注释注释的对象中的所有字段,我们必须首先确定所有字段。Class.getFields()将只返回“可访问的公共字段”。这不符合要求。因此我们必须使用Class.getDeclaredFields().&nbsp;这反过来只返回“由类声明”的字段。为了获得所有字段,我们必须向上遍历目标对象的类型层次结构,并为每个类型处理其声明的字段。对于每个字段,我们必须区分一些情况:阿Field&nbsp;被标注为指定的注释。然后必须将给定的值应用于该字段。为了设置该值,该字段必须是(使)可访问且非最终的。AField&nbsp;未使用指定的注释进行注释。那么要区分三种情况:该字段具有原始类型。那么它就不是一个可以包含String字段的对象。该字段具有数组类型。那么它不能包含一个String字段。否则:该字段具有引用类型。然后必须(使其)可访问,以检查它是否设置了值,并在这种情况下再次递归处理其字段 1) 和 2)。要检查是否在字段上设置了注释,我们使用Field.getAnnotation(myAnnotationClass)wheremyAnnotationClass声明为Class<MyAnnotation>。但是我们必须注意一些额外的事情:只有在以下情况下Field.getAnnotation(myAnnotationClass)才会返回字段的注释它已设置(非常不言自明)MyAnnotation本身用@Retention(RetentionPolicy.RUNTIME).相应的代码如下所示:&nbsp;public static <T extends Annotation> void setValueOnAnnotatedFields(String s, Class<T> annotationClass, Object target) {&nbsp; &nbsp; if (target != null) {&nbsp; &nbsp; &nbsp; // traversing the type hierarchy upward to process fields declared in classes target's class extends&nbsp; &nbsp; &nbsp; Class<?> clazz = target.getClass();&nbsp; &nbsp; &nbsp; do {&nbsp; &nbsp; &nbsp; &nbsp; setValueOnAnnotatedDeclaredFields(s, annotationClass, target, clazz);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; while ((clazz = clazz.getSuperclass()) != null);&nbsp; &nbsp; }&nbsp; }&nbsp; private static <T extends Annotation> void setValueOnAnnotatedDeclaredFields(String s, Class<T> annotationClass, Object target, Class<?> clazz) {&nbsp; &nbsp; Field[] fields = clazz.getDeclaredFields();&nbsp; &nbsp; for (Field field : fields) {&nbsp; &nbsp; &nbsp; if (field.getAnnotation(annotationClass) != null) {&nbsp; &nbsp; &nbsp; &nbsp; set(field, target, s);&nbsp; &nbsp; &nbsp; } else if (!field.getType().isPrimitive() && !field.getType().isArray()) {&nbsp; &nbsp; &nbsp; &nbsp; setValueOnAnnotatedFields(s, annotationClass, get(field, target));&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; }&nbsp; protected static void set(Field field, Object target, String value) {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; makeFiieldAccessibleNotFinal(field, target);&nbsp; &nbsp; &nbsp; field.set(target, value);&nbsp; &nbsp; }&nbsp; &nbsp; catch (Exception e) {&nbsp; &nbsp; &nbsp; String message = String.format("Failed to set the value on field %s", target.getClass().getSimpleName() + "." + field.getName());&nbsp; &nbsp; &nbsp; throw new IllegalStateException(message, e);&nbsp; &nbsp; }&nbsp; }&nbsp; protected static Object get(Field field, Object target) {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; makeFiieldAccessibleNotFinal(field, target);&nbsp; &nbsp; &nbsp; return field.get(target);&nbsp; &nbsp; }&nbsp; &nbsp; catch (Exception e) {&nbsp; &nbsp; &nbsp; String message = String.format("Failed to get the value on field %s", target.getClass().getSimpleName() + "." + field.getName());&nbsp; &nbsp; &nbsp; throw new IllegalStateException(message, e);&nbsp; &nbsp; }&nbsp; }&nbsp; protected static void makeFiieldAccessibleNotFinal(Field field, Object target) {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; Field modifiersField = Field.class.getDeclaredField("modifiers");&nbsp; &nbsp; &nbsp; modifiersField.setAccessible(true);&nbsp; &nbsp; &nbsp; modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);&nbsp; &nbsp; }&nbsp; &nbsp; catch (Exception e) {&nbsp; &nbsp; &nbsp; String message = String.format("Failed to remove final declaration of field %s", field.getName());&nbsp; &nbsp; &nbsp; throw new IllegalStateException(message, e);&nbsp; &nbsp; }&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; field.setAccessible(true);&nbsp; &nbsp; }&nbsp; &nbsp; catch (Exception e) {&nbsp; &nbsp; &nbsp; String message = String.format("Failed to make field %s accessible", field.getName());&nbsp; &nbsp; &nbsp; throw new IllegalStateException(message, e);&nbsp; &nbsp; }&nbsp; }一个例子:&nbsp; public static void main(String[] args) {&nbsp; &nbsp; A a = new A();&nbsp; &nbsp; System.out.println(a); // s: null / b: [null]&nbsp; &nbsp; setValueOnAnnotatedFields("1", MyAnnotation.class, a);&nbsp; &nbsp; System.out.println(a); // s: 1 / b: [null]&nbsp; &nbsp; a.b = new B();&nbsp; &nbsp; setValueOnAnnotatedFields("2", MyAnnotation.class, a);&nbsp; &nbsp; System.out.println(a); // s: 2 / b: [a: 2 / b: null]&nbsp; }这意味着类A已经toString()实现了:@Overridepublic String toString() {&nbsp; return "s: " + s + " / b: [" + Optional.ofNullable(b).map(B::toString).orElse("null") + "]";}和类B已经toString()实现了这样的:@Overridepublic String toString() {&nbsp; return "a: " + a + " / b: " + b;}

慕森王

您可以使用 Java 反射 API 来检查您的类的字段:获取为每个字段声明的注解;检查您是否有注释..嗯,多亏了反射 API,这不是一件难事。
随时随地看视频慕课网APP

相关分类

Java
我要回答