mysql java注解_Java 修改注解属性的工具类?

起初一看,我印象中是不行的,因为我一直以为XXX.class.getAnnotation(XXXAnnotation.class)这个方法是一个native方法

直到刚自己去看了一眼,哎呀,不是native方法啊

0470f7e0898320da0d9b41f3a3ca025c.png

好家伙,源来氏Class类中有一个私有内部静态类AnnotationData负责存储Class的注解里的值(前提你的注解是RetentionPolicy.RUNTIME的),当然存法也很简单就是用一个map存储了注解类型和注解实例

9ede29704700579e00dd090871f829fb.png

0b46d71d0425be92d5be4a3183af2564.png

所以看起来直接去修改对应Class的AnnotationData属性中的annotations map里的注解实例就可以了

但是其实不然,因为我们反射是拿不到反射相关类的属性的,例如Class,Field这些,不然那可不乱了套了(相当于搁这搁这这种套娃操作了...),因此呢只能再换个思路

我们可以注意到,虽然注解实例缓存在Class中,但是它确实可以通过getAnnotation获取到对应的实例,而这个实例恰好是一个代理对象,其实也就是用咱们jdk动态代理做的,只用debug一看就很清楚了

b8294c62b3a1517de1d79546fc8312f5.png

既然是代理对象,那肯定有对应的InvocationHandler啊,既然代理对象能够实现原注解的所有功能,那意味着其对应的InvocationHandler肯定也包含了该注解的所有功能。

果不其然,注解对应InvocationHandler是AnnotationInvocationHandler,这个类就很憨厚了,其中的memberValues属性就是我们需要的,怎么证实呢?

e3ea2d6c3b338d370c1fb4d74e1963f1.png

比如我们有个注解TestAnnotation@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface TestAnnotation {

String value();

}

注解到一个叫Test的类上,value值就写成haha

a97195d7749317c55fa3fc1629c5ac88.png

我们直接通过getAnnotation拿到对应的注解,再用Proxy.getInvocationHandler拿到对应的InvocationHandlerTestAnnotation testAnnotation = Test.class.getDeclaredAnnotation(TestAnnotation.class);

InvocationHandler invocationHandler = Proxy.getInvocationHandler(testAnnotation);

这个debug一看就很明显啦

8be6335314f9fda1325b9e71a892d5ea.png

memberValues中就藏着我们的目标,所以我们可以直接通过反射修改它就可以了,比如这样TestAnnotation annotation = Test.class.getAnnotation(TestAnnotation.class);

System.out.println("before value: " + annotation.value());

InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);

Field value = invocationHandler.getClass().getDeclaredField("memberValues");

value.setAccessible(true);

Map memberValues = (Map) value.get(invocationHandler);

memberValues.put("value", "i am new value");

annotation = Test.class.getAnnotation(TestAnnotation.class);

System.out.println("after value: " + annotation.value());

最终打印效果:

76f469567fcbdd380ff3bf74a38e3ea2.png

但是这样有个问题,什么呢?就是注解不仅仅是可以注解在类上的,也可以注解在字段上,方法上,所以我后面看了一下字段和方法上是怎么实现这个getAnnotation,那肯定就不是用AnnotationData啦,毕竟人家是Class的内部类

Field呢是内部有个私有declaredAnnotations属性,是Map, Annotation>的类型,那这个就和AnnotationData里的annotations类似啦

0ac888ef949eb7e3ee8ee3f302a62d7c.png

而Method是其父类Executable有个declaredAnnotations属性,还是Map, Annotation>类型

3be9f7266396ba3ad8869bdd55578931.png

那说明无论是怎么获取注解,都是从某个地方的Map, Annotation>缓存中获取。那怎么把不同地方,例如类,方法,字段聚合在一个工具类中呢?

铛铛铛!恰好有个顶层的接口把它们聚在了一起AnnotatedElement。因此工具方法应运而生(其实他们的getAnnotation方法就是来自AnnotatedElement接口的方法)public static void modify(AnnotatedElement element,

Class extends Annotation> annotationClass,

String key, Object value) throws NoSuchFieldException, IllegalAccessException {

Annotation annotationToBeModified = element.getAnnotation(annotationClass);

if (annotationToBeModified == null) return;

InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotationToBeModified);

Field memberValuesField = invocationHandler.getClass().getDeclaredField("memberValues");

memberValuesField.setAccessible(true);

Map memberValues = (Map) memberValuesField.get(invocationHandler);

memberValues.put(key, value);

}

参数也很好理解,AnnotatedElement就是被注解的地方啦,如果呢你是注解的类,就传Class,注解的方法,就传某个Method,注解的是字段,就传Field,就算注解的参数,那就传某个Parameter,总之理论上啥都够啦

最后题主提到的MySQL那就不是大问题啦,毕竟它只是一个数据库而已,如果真有某个工具可以实现题主的需求,那提供这个工具的人也太嘞了。。。竟然必须要MySQL,所以啊,这个问题最大的点应该还是如何实现运行时修改注解里的值,不过最后实现下来看起来也没多少代码,只是一个小工具,可以放到自己项目中进行一些组装成为其他业务组件的一个部分吧。

那就酱。。。o( ̄▽ ̄)d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值