如何动态修改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(Map map,StringparamName){ for(Map.Entry entry:map.entrySet()){ if(entry.getKey().equals(paramName)){ returnentry.getValue(); } } returnnull; } /** *获取方法的参数名和值 * *@paramjoinPoint *@return */ publicMap getParams(JoinPointjoinPoint){ Map params=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:测试注解传递简单动态参数以上为个人经验,希望能给大家一个参考,也希望大家多多支持毛票票。如有错误或未考虑完全的地方,望不吝赐教。