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

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

想象一下有一个类:

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

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

这个是可能的吗?如果是,怎么做?


牧羊人nacy
浏览 768回答 3
3回答

倚天杖

在OSX上测试过。效果很好。由于我还需要在运行时更改注释值,所以我重新讨论了这个问题。下面是@assylias方法的修改版本(非常感谢您的启发)。/** &nbsp;*&nbsp;Changes&nbsp;the&nbsp;annotation&nbsp;value&nbsp;for&nbsp;the&nbsp;given&nbsp;key&nbsp;of&nbsp;the&nbsp;given&nbsp;annotation&nbsp;to&nbsp;newValue&nbsp;and&nbsp;returns &nbsp;*&nbsp;the&nbsp;previous&nbsp;value. &nbsp;*/@SuppressWarnings("unchecked")public&nbsp;static&nbsp;Object&nbsp;changeAnnotationValue(Annotation&nbsp;annotation,&nbsp;String&nbsp;key,&nbsp;Object&nbsp;newValue){ &nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;handler&nbsp;=&nbsp;Proxy.getInvocationHandler(annotation); &nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;f; &nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&nbsp;=&nbsp;handler.getClass().getDeclaredField("memberValues"); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(NoSuchFieldException&nbsp;|&nbsp;SecurityException&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;IllegalStateException(e); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;f.setAccessible(true); &nbsp;&nbsp;&nbsp;&nbsp;Map<String,&nbsp;Object>&nbsp;memberValues; &nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memberValues&nbsp;=&nbsp;(Map<String,&nbsp;Object>)&nbsp;f.get(handler); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;catch&nbsp;(IllegalArgumentException&nbsp;|&nbsp;IllegalAccessException&nbsp;e)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;IllegalStateException(e); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;oldValue&nbsp;=&nbsp;memberValues.get(key); &nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(oldValue&nbsp;==&nbsp;null&nbsp;||&nbsp;oldValue.getClass()&nbsp;!=&nbsp;newValue.getClass())&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw&nbsp;new&nbsp;IllegalArgumentException(); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;memberValues.put(key,newValue); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;oldValue;}用法示例:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public&nbsp;@interface&nbsp;ClassAnnotation&nbsp;{ &nbsp;&nbsp;String&nbsp;value()&nbsp;default&nbsp;"";}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public&nbsp;@interface&nbsp;FieldAnnotation&nbsp;{ &nbsp;&nbsp;String&nbsp;value()&nbsp;default&nbsp;"";}@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public&nbsp;@interface&nbsp;MethodAnnotation&nbsp;{ &nbsp;&nbsp;String&nbsp;value()&nbsp;default&nbsp;"";}@ClassAnnotation("class&nbsp;test")public&nbsp;static&nbsp;class&nbsp;TestClass{ &nbsp;&nbsp;&nbsp;&nbsp;@FieldAnnotation("field&nbsp;test") &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Object&nbsp;field; &nbsp;&nbsp;&nbsp;&nbsp;@MethodAnnotation("method&nbsp;test") &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;method(){ &nbsp;&nbsp;&nbsp;&nbsp;}}public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;ClassAnnotation&nbsp;classAnnotation&nbsp;=&nbsp;TestClass.class.getAnnotation(ClassAnnotation.class); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("old&nbsp;ClassAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;classAnnotation.value()); &nbsp;&nbsp;&nbsp;&nbsp;changeAnnotationValue(classAnnotation,&nbsp;"value",&nbsp;"another&nbsp;class&nbsp;annotation&nbsp;value"); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("modified&nbsp;ClassAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;classAnnotation.value()); &nbsp;&nbsp;&nbsp;&nbsp;Field&nbsp;field&nbsp;=&nbsp;TestClass.class.getField("field"); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;FieldAnnotation&nbsp;fieldAnnotation&nbsp;=&nbsp;field.getAnnotation(FieldAnnotation.class); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("old&nbsp;FieldAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;fieldAnnotation.value()); &nbsp;&nbsp;&nbsp;&nbsp;changeAnnotationValue(fieldAnnotation,&nbsp;"value",&nbsp;"another&nbsp;field&nbsp;annotation&nbsp;value"); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("modified&nbsp;FieldAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;fieldAnnotation.value()); &nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;method&nbsp;=&nbsp;TestClass.class.getMethod("method"); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;MethodAnnotation&nbsp;methodAnnotation&nbsp;=&nbsp;method.getAnnotation(MethodAnnotation.class); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("old&nbsp;MethodAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;methodAnnotation.value()); &nbsp;&nbsp;&nbsp;&nbsp;changeAnnotationValue(methodAnnotation,&nbsp;"value",&nbsp;"another&nbsp;method&nbsp;annotation&nbsp;value"); &nbsp;&nbsp;&nbsp;&nbsp;System.out.println("modified&nbsp;MethodAnnotation&nbsp;=&nbsp;"&nbsp;+&nbsp;methodAnnotation.value());}这种方法的优点是不需要创建新的注释实例。因此,不需要预先知道具体的注释类。另外,副作用应该是最小的,因为原始的注释实例保持不变。用Java 8进行测试。

哔哔one

这个在我的机器上用Java 8工作。ignoreUnknown在注释中@JsonIgnoreProperties(ignoreUnknown = true)从…千真万确到假的.final&nbsp;List<Annotation>&nbsp;matchedAnnotation&nbsp;=&nbsp;Arrays.stream(SomeClass.class.getAnnotations()).filter(annotation&nbsp;->&nbsp;annotation.annotationType(). equals(JsonIgnoreProperties.class)).collect(Collectors.toList());&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Annotation&nbsp;modifiedAnnotation&nbsp;=&nbsp;new&nbsp;JsonIgnoreProperties()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;public&nbsp;Class<?&nbsp;extends&nbsp;Annotation>&nbsp;annotationType()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;matchedAnnotation.get(0).annotationType(); &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;public&nbsp;String[]&nbsp;value()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;String[0]; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;public&nbsp;boolean&nbsp;ignoreUnknown()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;public&nbsp;boolean&nbsp;allowGetters()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;@Override&nbsp;public&nbsp;boolean&nbsp;allowSetters()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false; &nbsp;&nbsp;&nbsp;&nbsp;}};&nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Method&nbsp;method&nbsp;=&nbsp;Class.class.getDeclaredMethod("getDeclaredAnnotationMap",&nbsp;null);method.setAccessible(true); &nbsp;&nbsp;&nbsp;&nbsp;final&nbsp;Map<Class<?&nbsp;extends&nbsp;Annotation>,&nbsp;Annotation>&nbsp;annotations&nbsp;=&nbsp;(Map<Class<?&nbsp;extends&nbsp;Annotation>,&nbsp;Annotation>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;method.invoke(SomeClass.class,&nbsp;null);annotations.put(JsonIgnoreProperties.class,&nbsp;modifiedAnnotation);
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java
React.JS