如何动态修改JavaBean中注解的参数值
我这里有一个需求需要修改Person类中的一个属性上的注解的值进行修改,例如:
publicclassPerson{
privateintage;
@ApiParam(access="lala")
privateStringname;
//getset方法忽略
}
将@ApiParam(access=“lala”)修改为@ApiParam(access=“fafa”),经过分析是可以实现的,需要用到动态代理进行操作。
具体源码如下所示:
@Target({ElementType.PARAMETER,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public@interfaceApiParam{
Stringaccess()default"";
}
反射+动态代理代码如下:
publicclassTestClazz{
publicstaticvoidmain(String[]args)throwsNoSuchFieldException,SecurityException,IllegalArgumentException,IllegalAccessException{
Personperson=newPerson();
Fieldvalue=person.getClass().getDeclaredField("name");
value.setAccessible(true);
//APIParam是一个自定义的注解
ApiParamapiParam=(ApiParam)value.getAnnotation(ApiParam.class);
java.lang.reflect.InvocationHandlerinvocationHandler=Proxy.getInvocationHandler(apiParam);
FieldmemberValues=invocationHandler.getClass().getDeclaredField("memberValues");
//通过反射获取memberValues这个属性是Map类型存放着所有的属性。
memberValues.setAccessible(true);
Mapvalues=(Map)memberValues.get(invocationHandler);
Stringval=(String)values.get("access");
System.out.println("------改之前:"+val);
values.put("access","fafa");//修改属性
System.out.println("-----------------");
//Fieldvalue1=person.getClass().getDeclaredField("name");
value.setAccessible(true);
ApiParamapiParam1=(ApiParam)value.getAnnotation(ApiParam.class);
System.out.println("------改之后:"+apiParam1.access());
//动态代理的方式不会改变原先class文件的内容
}
}
补充:Java自定义注解并实现注解的伪动态参数传递
自定义注解,实现记录接口的调用日志,此注解可以实现传递伪动态参数。
一、需要引入的jar包:
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test org.springframework.boot spring-boot-test org.springframework.boot spring-boot-starter-aop commons-lang commons-lang 2.4 org.apache.commons commons-lang3 commons-beanutils commons-beanutils 1.8.0 commons-collections commons-collections 3.2.1 commons-logging commons-logging 1.1.1 net.sf.json-lib json-lib 2.4
二、自定义注解:
packagecom.example.demo.annotation;
importjava.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public@interfaceApiOperationLog{
StringresourceId()default"";
StringoperationType();
Stringdescription()default"";
}
三、定义切面:
packagecom.example.demo.aspect;
importcom.example.demo.annotation.ApiOperationLog;
importnet.sf.json.JSONObject;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.annotation.AfterReturning;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.stereotype.Component;
importjava.util.HashMap;
importjava.util.Map;
@Aspect
@Component
publicclassApiOperationAspect{
@Pointcut("@annotation(com.example.demo.annotation.ApiOperationLog)")
publicvoidapiLog(){
}
@AfterReturning(pointcut="apiLog()")
publicvoidrecordLog(JoinPointjoinPoint){
MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();
//获取方法上的指定注解
ApiOperationLogannotation=signature.getMethod().getAnnotation(ApiOperationLog.class);
//获取注解中的参数
StringresourceId=getAnnotationValue(joinPoint,annotation.resourceId());
StringoperationType=getAnnotationValue(joinPoint,annotation.operationType());
Stringdescription=getAnnotationValue(joinPoint,annotation.description());
System.out.println("resourceId:"+resourceId);
System.out.println("operationType:"+operationType);
System.out.println("description:"+description);
//将注解中测参数值保存到数据库,实现记录接口调用日志的功能(以下内容省略...)
}
/**
*获取注解中传递的动态参数的参数值
*
*@paramjoinPoint
*@paramname
*@return
*/
publicStringgetAnnotationValue(JoinPointjoinPoint,Stringname){
StringparamName=name;
//获取方法中所有的参数
Mapparams=getParams(joinPoint);
//参数是否是动态的:#{paramName}
if(paramName.matches("^#\\{\\D*\\}")){
//获取参数名
paramName=paramName.replace("#{","").replace("}","");
//是否是复杂的参数类型:对象.参数名
if(paramName.contains(".")){
String[]split=paramName.split("\\.");
//获取方法中对象的内容
Objectobject=getValue(params,split[0]);
//转换为JsonObject
JSONObjectjsonObject=JSONObject.fromObject(object);
//获取值
Objecto=jsonObject.get(split[1]);
returnString.valueOf(o);
}
//简单的动态参数直接返回
returnString.valueOf(getValue(params,paramName));
}
//非动态参数直接返回
returnname;
}
/**
*根据参数名返回对应的值
*
*@parammap
*@paramparamName
*@return
*/
publicObjectgetValue(Mapmap,StringparamName){
for(Map.Entryentry:map.entrySet()){
if(entry.getKey().equals(paramName)){
returnentry.getValue();
}
}
returnnull;
}
/**
*获取方法的参数名和值
*
*@paramjoinPoint
*@return
*/
publicMapgetParams(JoinPointjoinPoint){
Mapparams=newHashMap<>(8);
Object[]args=joinPoint.getArgs();
MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();
String[]names=signature.getParameterNames();
for(inti=0;i
四:测试前的准备内容:
//实体类
packagecom.example.demo.model;
publicclassUser{
privateLongid;
privateStringname;
privateintage;
publicLonggetId(){
returnid;
}
publicvoidsetId(Longid){
this.id=id;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
@Override
publicStringtoString(){
return"User{"+
"id="+id+
",name='"+name+'\''+
",age="+age+
'}';
}
}
//controller层内容
packagecom.example.demo.controller;
importcom.example.demo.annotation.ApiOperationLog;
importcom.example.demo.model.User;
importorg.springframework.web.bind.annotation.RestController;
@RestController
publicclassLoginController{
@ApiOperationLog(resourceId="#{user.id}",operationType="SAVE",description="测试注解传递复杂动态参数")
publicvoidsaveUser(Useruser,Stringid){
System.out.println("测试注解...");
}
@ApiOperationLog(resourceId="#{id}",operationType="UPDATE",description="测试注解传递简单动态参数")
publicvoidupdateUser(Useruser,Stringid){
System.out.println("测试注解...");
}
}
五、测试类:
packagecom.example.demo.aspect;
importcom.example.demo.DemoApplication;
importcom.example.demo.controller.LoginController;
importcom.example.demo.model.User;
importorg.junit.Test;
importorg.junit.runner.RunWith;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.test.context.SpringBootTest;
importorg.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=DemoApplication.class)
publicclassControllerTest{
@Autowired
privateLoginControllerloginController;
@Test
publicvoidtest(){
Useruser=newUser();
user.setId(1L);
user.setName("test");
user.setAge(20);
loginController.saveUser(user,"123");
loginController.updateUser(user,"666");
}
}
测试结果:
测试注解...
resourceId:1
operationType:SAVE
description:测试注解传递复杂动态参数
测试注解...
resourceId:666
operationType:UPDATE
description:测试注解传递简单动态参数
以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。