Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在运行时使用Java反射API修改字段的声明注释_Java_Reflection - Fatal编程技术网

在运行时使用Java反射API修改字段的声明注释

在运行时使用Java反射API修改字段的声明注释,java,reflection,Java,Reflection,通过创建和安装新的内部AnnotationData对象,可以在运行时向Java类添加注释。我很好奇是否可以设置一个字段。似乎字段处理注释的方式与类处理注释的方式截然不同 我已经能够使用以下类成功地向字段类的declaredAnnotations字段添加注释: public class FieldRuntimeAnnotations { private static final Field DECLARED_ANNOTATIONS_FIELD; private static final

通过创建和安装新的内部
AnnotationData
对象,可以在运行时向Java类添加注释。我很好奇是否可以设置一个
字段
。似乎
字段
处理注释的方式与
处理注释的方式截然不同

我已经能够使用以下类成功地向
字段
类的
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);
    }
  }
}

我明白我想要达到的目标是相当荒谬的,但我很享受这个练习:D。。。有什么想法吗?

使用TestEntity.class.getDeclaredField(“test”)可以获得TestEntity.class的私有内部字段的副本,但需要原始字段。 我扩展了您的测试用例,从Class.Class中的私有方法“privateGetDeclaredFields”获取原始私有字段

import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.junit.Assert;
import org.junit.Test;

public class FieldRuntimeAnnotationsTest {
    @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);

        // This field is a copy of the internal one
        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 not updated -- THE FIELD IS A COPY
        Assert.assertNull(TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class));

        // Repeat the process with the internal field
        Field f2 = getDeclaredField(TestEntity.class, "test");
        f2.setAccessible(true);

        FieldRuntimeAnnotations.putAnnotationToField(f2, TestAnnotation.class, new HashMap<>());

        // Make sure field annotation gets set
        Assert.assertNotNull(f2.getAnnotation(TestAnnotation.class));

        // Make sure the class that contains that field is also updated -- THE FIELD IS THE ORIGINAL ONE
        Assert.assertNotNull(TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class));
    }

    public Field getDeclaredField(Class<?> clazz, String name) {
        if (name == null || name.isEmpty()) {
            return null;
        }
        Field[] fields = getDeclaredFields(clazz);
        Field field = null;
        for (Field f : fields) {
            if (name.equals(f.getName())) {
                field = f;
            }
        }
        return field;
    }

    public Field[] getDeclaredFields(Class<?> clazz) {
        if (clazz == null) {
            return new Field[0];
        }
        Method privateGetDeclaredFieldsMethod = null;
        Object value = null;
        try {
            privateGetDeclaredFieldsMethod = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
            privateGetDeclaredFieldsMethod.setAccessible(true);
            value = privateGetDeclaredFieldsMethod.invoke(clazz, Boolean.FALSE);
        }
        catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            Assert.fail("Error for " + clazz + ", exception=" + e.getMessage());
    }
        Field[] fields = value == null ? new Field[0] : (Field[])value;
        return fields;
    }
}
import java.lang.annotation.RetentionPolicy;
导入java.lang.annotation.ElementType;
导入java.lang.annotation.Retention;
导入java.lang.annotation.Target;
导入java.lang.reflect.Field;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Method;
导入java.util.HashMap;
导入java.util.Map;
导入org.junit.Assert;
导入org.junit.Test;
公共类FieldRuntimeAnnotationsTest{
@保留(RetentionPolicy.RUNTIME)
@目标({ElementType.TYPE,ElementType.FIELD})
public@interface TestAnnotation{}
公共静态类测试{
私有字符串测试;
}
@试验
public void testPutAnnotationToField()抛出NoSuchFieldException{
//确认类没有注释
TestAnnotation=TestEntity.class.getDeclaredField(“测试”).getAnnotation(TestAnnotation.class);
Assert.assertNull(注释);
//此字段是内部字段的副本
字段f=TestEntity.class.getDeclaredField(“测试”);
f、 setAccessible(true);
FieldRuntimeAnnotations.putAnnotationToField(f,TestAnnotations.class,new HashMap());
//确保设置了字段注释
Assert.assertNotNull(f.getAnnotation(TestAnnotation.class));
//确保包含该字段的类未更新--该字段是副本
Assert.assertNull(TestEntity.class.getDeclaredField(“test”).getAnnotation(TestAnnotation.class));
//对内部字段重复该过程
字段f2=getDeclaredField(TestEntity.class,“测试”);
f2.可访问设置(真);
FieldRuntimeAnnotations.putAnnotationToField(f2,TestAnnotation.class,new HashMap());
//确保设置了字段注释
Assert.assertNotNull(f2.getAnnotation(TestAnnotation.class));
//确保包含该字段的类也已更新——该字段是原始字段
Assert.assertNotNull(TestEntity.class.getDeclaredField(“test”).getAnnotation(TestAnnotation.class));
}
公共字段getDeclaredField(类clazz,字符串名称){
if(name==null | | name.isEmpty()){
返回null;
}
字段[]字段=getDeclaredFields(clazz);
字段=空;
用于(字段f:字段){
if(name.equals(f.getName())){
字段=f;
}
}
返回字段;
}
公共字段[]getDeclaredFields(类clazz){
if(clazz==null){
返回新字段[0];
}
方法privateGetDeclaredFieldsMethod=null;
对象值=空;
试一试{
privateGetDeclaredFieldsMethod=Class.Class.getDeclaredMethod(“privateGetDeclaredFields”,boolean.Class);
privateGetDeclaredFieldsMethod.setAccessible(true);
value=privateGetDeclaredFieldsMethod.invoke(clazz,Boolean.FALSE);
}
捕获(NoSuchMethodException | IllegalacessException | InvocationTargetException e){
Assert.fail(“错误为“+clazz+”,异常为“+e.getMessage()”);
}
字段[]字段=value==null?新字段[0]:(字段[])值;
返回字段;
}
}

非常有魅力!我错过了调用
Class.Class
方法
privateGetDeclaredFields
的关键部分,该方法使用带有布尔参数
false
的字段声明类。非常感谢。
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.junit.Assert;
import org.junit.Test;

public class FieldRuntimeAnnotationsTest {
    @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);

        // This field is a copy of the internal one
        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 not updated -- THE FIELD IS A COPY
        Assert.assertNull(TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class));

        // Repeat the process with the internal field
        Field f2 = getDeclaredField(TestEntity.class, "test");
        f2.setAccessible(true);

        FieldRuntimeAnnotations.putAnnotationToField(f2, TestAnnotation.class, new HashMap<>());

        // Make sure field annotation gets set
        Assert.assertNotNull(f2.getAnnotation(TestAnnotation.class));

        // Make sure the class that contains that field is also updated -- THE FIELD IS THE ORIGINAL ONE
        Assert.assertNotNull(TestEntity.class.getDeclaredField("test").getAnnotation(TestAnnotation.class));
    }

    public Field getDeclaredField(Class<?> clazz, String name) {
        if (name == null || name.isEmpty()) {
            return null;
        }
        Field[] fields = getDeclaredFields(clazz);
        Field field = null;
        for (Field f : fields) {
            if (name.equals(f.getName())) {
                field = f;
            }
        }
        return field;
    }

    public Field[] getDeclaredFields(Class<?> clazz) {
        if (clazz == null) {
            return new Field[0];
        }
        Method privateGetDeclaredFieldsMethod = null;
        Object value = null;
        try {
            privateGetDeclaredFieldsMethod = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
            privateGetDeclaredFieldsMethod.setAccessible(true);
            value = privateGetDeclaredFieldsMethod.invoke(clazz, Boolean.FALSE);
        }
        catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            Assert.fail("Error for " + clazz + ", exception=" + e.getMessage());
    }
        Field[] fields = value == null ? new Field[0] : (Field[])value;
        return fields;
    }
}