当前位置: 首页 > news >正文

字节码编程javassist之获取方法参数类型,参数值列表,返回值等

写在前面

本文看下如何获取方法参数名称,参数值,返回值等。

1:代码

  • 需要增强的类:
public class ApiTest1 {public Integer strToInt(String str01, String str02) {return Integer.parseInt(str01);}}
  • 插桩类
package com.dahuyou.javassist.huohuo.aa;import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.LongConsumer;public class MyDoIt extends ClassLoader {public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();// 获取类和方法CtClass ctClass = pool.get(ApiTest1.class.getName());ctClass.replaceClassName("ApiTest1", "ApiTest12");String clazzName = ctClass.getName();CtMethod ctMethod = ctClass.getDeclaredMethod("strToInt");// 方法信息:methodInfo.getDescriptor();MethodInfo methodInfo = ctMethod.getMethodInfo();// 方法:入参信息CodeAttribute codeAttribute = methodInfo.getCodeAttribute();// 获取局部变量表信息(位置1就是第一次参数,位置2就是第二个参数,以此类推。。。)LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);CtClass[] parameterTypes = ctMethod.getParameterTypes();// 获取局部变量表的长度boolean isStatic = (methodInfo.getAccessFlags() & AccessFlag.STATIC) != 0;  // 判断是否为静态方法int parameterSize = isStatic ? attr.tableLength() : attr.tableLength() - 1; // 静态类型取值// 参数的名称List<String> parameterNameList = new ArrayList<>(parameterSize);// 参数的类型List<String> parameterTypeList = new ArrayList<>(parameterSize);// 参数值StringBuilder parameters = new StringBuilder();for (int i = 0; i < parameterSize; i++) {// 非静态类型去掉第一个this参数parameterNameList.add(attr.variableName(i + (isStatic ? 0 : 1)));parameterTypeList.add(parameterTypes[i].getName());if (i + 1 == parameterSize) {parameters.append("$").append(i + 1);} else {parameters.append("$").append(i + 1).append(",");}}// 方法:出参信息CtClass returnType = ctMethod.getReturnType();String returnTypeName = returnType.getName();String parameterNameListValue = parameterNameList.toString();String parameterTypeListValue = parameterTypeList.toString();
//        String parametersValue = parameters.toString();
//        ctMethod.addLocalVariable("");// System.out.println("参数的名称:" + parameterNameList + ", 参数的类型:" + parameterTypeList + ", 参数的值:" + parameters);
//        ctMethod.insertBefore("System.out.println(\"参数的名称:" + parameterNameListValue + ", 参数的类型:" + parameterTypeListValue + ", 参数的值:" + parametersValue + "\");");ctMethod.addLocalVariable("parametersValue", pool.get(String.class.getName()));
//        ctMethod.insertBefore("parametersValue=" + parameters.toString() + "; System.out.println(\"参数的名称:" + parameterNameListValue + ", 参数的类型:" + parameterTypeListValue + ", 参数的值:parametersValue;\");");ctMethod.insertBefore("parametersValue=\"\";parametersValue+=$1;parametersValue+=\",\";parametersValue+=$2; System.out.println(\"参数的名称:" + parameterNameListValue + ", 参数的类型:" + parameterTypeListValue + ", 参数的值\"+parametersValue+\";\");");ctMethod.insertBefore("System.out.println(\"返回值类型:" + returnTypeName + "\");");ctMethod.addLocalVariable("returnVal", pool.get(Integer.class.getName()));
//        ctMethod.addLocalVariable("returnVal", CtClass.intType);
//        ctMethod.insertAfter("returnVal=$_;System.out.println(\"返回值:\"+returnVal+\"\");");ctMethod.insertAfter("returnVal=$_;");
//        ctMethod.insertAfter("System.out.println(\"返回值:\"+returnVal+\"\");");ctMethod.insertAfter("{ com.dahuyou.javassist.huohuo.aa.MyDoIt.show(returnVal);}", false); // 如果返回类型非对象类型,$_ 需要进行类型转换ctMethod.insertAfter("{ com.dahuyou.javassist.huohuo.aa.MyDoIt.show($_);}", false); // 如果返回类型非对象类型,$_ 需要进行类型转换ctClass.writeFile();// 测试调用byte[] bytes = ctClass.toBytecode();Class<?> clazzNew = new MyDoIt().defineClass("com.dahuyou.javassist.huohuo.aa.ApiTest1", bytes, 0, bytes.length);// 反射运行测试Class aClass = clazzNew;Object obj = aClass.newInstance();Method main = aClass.getDeclaredMethod("strToInt", String.class, String.class);main.invoke(obj, "99", "87");//        System.out.println("执行耗时:" + (System.nanoTime() - startTime));}//    private static void show(Object param) {public static void show(Integer param) {System.out.println("返回值:" + param);}
}

运行:

返回值类型:java.lang.Integer
参数的名称:[str01, str02], 参数的类型:[java.lang.String, java.lang.String], 参数的值99,87;
返回值:99
返回值:99Process finished with exit code 0

需要注意的点:

1:入参信息的获取依赖于局部变量表
2:$_代表方法的返回值,但必须通过方法insertAfter插入到方法结尾,因为只有在结尾处才有返回值这一说

写在后面

参考文章列表

相关文章:

  • mysql怎么调整缓冲区大小
  • 游戏开发面试题3
  • 第二十九天 第八章 贪心算法 part03 134. 加油站 135. 分发糖果 860.柠檬水找零 406.根据身高重建队列
  • 掌握【Python异常处理】:打造健壮代码的现代编程指南
  • flutter背景贴图的困难总结
  • LDRA Testbed(TBrun)软件单元测试_实例讲解(指针类型的处理)
  • 自然语言处理与Transformer模型:革新语言理解的新时代
  • LlamaGen:自回归模型的图像生成革命
  • 大语言模型系列-Transformer
  • 人工智能概论 | 基于A*算法的8数码问题求解
  • 绝区肆--2024 年AI安全状况
  • wordpress网站添加一个临时维护功能
  • 车辆出险报告API接口及使用
  • 算法数据结构必备篇章2
  • 5.opencv深浅拷贝
  • $translatePartialLoader加载失败及解决方式
  • 【附node操作实例】redis简明入门系列—字符串类型
  • CSS魔法堂:Absolute Positioning就这个样
  • HomeBrew常规使用教程
  • Laravel 菜鸟晋级之路
  • Linux各目录及每个目录的详细介绍
  • log4j2输出到kafka
  • PAT A1050
  • React中的“虫洞”——Context
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Vue2 SSR 的优化之旅
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webpack+react项目初体验——记录我的webpack环境配置
  • webpack4 一点通
  • 前端面试之CSS3新特性
  • 由插件封装引出的一丢丢思考
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • # 数据结构
  • #Z0458. 树的中心2
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)计算机毕业设计ssm电影分享网站
  • (算法)求1到1亿间的质数或素数
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (源码分析)springsecurity认证授权
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)大型网站架构演变和知识体系
  • ***原理与防范
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .mp4格式的视频为何不能通过video标签在chrome浏览器中播放?
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .net6 当连接用户的shell断掉后,dotnet会自动关闭,达不到长期运行的效果。.NET 进程守护
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET企业级应用架构设计系列之开场白
  • //usr/lib/libgdal.so.20:对‘sqlite3_column_table_name’未定义的引用
  • @Transaction注解失效的几种场景(附有示例代码)
  • [ SNOI 2013 ] Quare
  • [12] 使用 CUDA 进行图像处理
  • [20161101]rman备份与数据文件变化7.txt