java - 在运行时修改类定义的注释字符串参数

标签 java reflection

假设有一个类:

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

它已经编译好了(我无法控制源代码),并且是 jvm 启动时类路径的一部分。我希望能够在运行时将“某些值”更改为其他值,以便此后的任何反射都将具有我的新值而不是默认的“某些值”。

这可能吗?如果是这样,怎么办?

最佳答案

警告:未在 OSX 上进行测试 - 请参阅 @Marcel 的评论

在 OSX 上测试。工作正常。

由于我也需要在运行时更改注释值,因此我重新审视了这个问题。

这是 @assylias 方法的修改版本(非常感谢您的启发)。

/**
 * Changes the annotation value for the given key of the given annotation to newValue and returns
 * the previous value.
 */
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
    Object handler = Proxy.getInvocationHandler(annotation);
    Field f;
    try {
        f = handler.getClass().getDeclaredField("memberValues");
    } catch (NoSuchFieldException | SecurityException e) {
        throw new IllegalStateException(e);
    }
    f.setAccessible(true);
    Map<String, Object> memberValues;
    try {
        memberValues = (Map<String, Object>) f.get(handler);
    } catch (IllegalArgumentException | IllegalAccessException e) {
        throw new IllegalStateException(e);
    }
    Object oldValue = memberValues.get(key);
    if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
        throw new IllegalArgumentException();
    }
    memberValues.put(key,newValue);
    return oldValue;
}

使用示例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassAnnotation {
  String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnnotation {
  String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnnotation {
  String value() default "";
}
@ClassAnnotation("class test")
public static class TestClass{
    @FieldAnnotation("field test")
    public Object field;
    @MethodAnnotation("method test")
    public void method(){

    }
}

public static void main(String[] args) throws Exception {
    final ClassAnnotation classAnnotation = TestClass.class.getAnnotation(ClassAnnotation.class);
    System.out.println("old ClassAnnotation = " + classAnnotation.value());
    changeAnnotationValue(classAnnotation, "value", "another class annotation value");
    System.out.println("modified ClassAnnotation = " + classAnnotation.value());

    Field field = TestClass.class.getField("field");
    final FieldAnnotation fieldAnnotation = field.getAnnotation(FieldAnnotation.class);
    System.out.println("old FieldAnnotation = " + fieldAnnotation.value());
    changeAnnotationValue(fieldAnnotation, "value", "another field annotation value");
    System.out.println("modified FieldAnnotation = " + fieldAnnotation.value());

    Method method = TestClass.class.getMethod("method");
    final MethodAnnotation methodAnnotation = method.getAnnotation(MethodAnnotation.class);
    System.out.println("old MethodAnnotation = " + methodAnnotation.value());
    changeAnnotationValue(methodAnnotation, "value", "another method annotation value");
    System.out.println("modified MethodAnnotation = " + methodAnnotation.value());
}

这种方法的优点是,不需要创建新的注释实例。因此不需要提前知 Prop 体的注解类。此外,副作用应该是最小的,因为原始注释实例保持不变。

使用 Java 8 进行测试。

关于java - 在运行时修改类定义的注释字符串参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62215421/

相关文章:

c# - PropertyInfo.GetValue 返回枚举常量名称而不是值

java - 如何在 JavaFX 中以编程方式折叠 TitledPane?

java - org.springframework.orm.hibernate3.support.BlobByteArrayType 有什么用?

java - Android非法状态异常

java - 如何更新附加到 Workfront 项目的自定义字段?

c# - 将属性值与反射进行比较

c# - 如何检查类型是否实现了 ICollection<T>

reflection - 如何从 Lua 脚本获取有关函数调用的信息?

reflection - 我将如何发出受歧视的联盟?

java - 自定义 ForkJoinPool 中的嵌套 ArrayList.ParallelStream() 使用线程不均匀