如何解析JNI方法签名并获取其通用信息?求工具及实现建议
解析JNI方法签名的实用方案
一、用现成库快速解决
最省心的方案是用ASM(Java字节码操作常用工具),它的org.objectweb.asm.Type类原生支持JNI签名解析,不用自己写复杂的拆分逻辑:
- 先提取JNI签名中的方法签名段,比如从示例
Lme/jni/Clazz;->demo(Ljava/lang/String;IZ[I[[Z)V中拆分出(Ljava/lang/String;IZ[I[[Z)V - 用ASM的API解析并转换:
运行后直接得到目标结果:String jniSignature = "Lme/jni/Clazz;->demo(Ljava/lang/String;IZ[I[[Z)V"; // 拆分出类名、方法签名部分 String[] parts = jniSignature.split("->"); String className = parts[0].substring(1, parts[0].length()-1).replace("/", "."); String methodSig = parts[1]; // 解析方法类型 Type methodType = Type.getMethodType(methodSig); // 处理返回类型 String returnType = methodType.getReturnType().getClassName(); returnType = returnType.equals("java.lang.Void") ? "void" : returnType; // 处理参数类型 Type[] paramTypes = methodType.getArgumentTypes(); List<String> paramNames = new ArrayList<>(); for (Type type : paramTypes) { paramNames.add(type.getClassName()); } // 拼接成可读格式 String readable = String.format("%s: %s demo(%s)", className, returnType, String.join(",", paramNames));me.jni.Clazz: void demo(java.lang.String,int,boolean,int[],boolean[][])
ASM的Maven依赖可以直接添加:
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.5</version> </dependency>
二、自己实现解析逻辑(无依赖场景)
如果不想引入第三方库,可根据JNI签名规则手动扫描解析,核心是处理无分隔符的参数类型串,步骤如下:
1. 拆分JNI签名的核心部分
从输入签名中提取4个关键信息:
- 类名:
L开头到;->之前的内容,把/替换为.,比如Lme/jni/Clazz;→me.jni.Clazz - 方法名:
->之后到(之前的字符串,比如demo - 参数签名:
(和)之间的字符串,比如Ljava/lang/String;IZ[I[[Z - 返回类型签名:
)之后的字符串,比如V
2. 实现类型解析工具函数
写一个递归扫描函数,处理单个类型签名片段:
private static String parseType(String sig, int[] index) { char curr = sig.charAt(index[0]); switch (curr) { // 基本类型直接映射 case 'Z': index[0]++; return "boolean"; case 'B': index[0]++; return "byte"; case 'C': index[0]++; return "char"; case 'S': index[0]++; return "short"; case 'I': index[0]++; return "int"; case 'J': index[0]++; return "long"; case 'F': index[0]++; return "float"; case 'D': index[0]++; return "double"; case 'V': index[0]++; return "void"; // 引用类型:扫描到;结束,替换/为. case 'L': int end = sig.indexOf(';', index[0]); String className = sig.substring(index[0]+1, end).replace("/", "."); index[0] = end + 1; return className; // 数组类型:统计连续[的数量,再解析元素类型 case '[': int dim = 0; while (sig.charAt(index[0]) == '[') { dim++; index[0]++; } String elemType = parseType(sig, index); StringBuilder sb = new StringBuilder(elemType); for (int i=0; i<dim; i++) sb.append("[]"); return sb.toString(); default: throw new IllegalArgumentException("无效类型签名:" + curr); } }
3. 批量解析参数
用上面的函数遍历参数签名字符串,比如处理IZ[I[[Z:
- 第一个字符
I→int,指针后移1位 - 第二个字符
Z→boolean,指针后移1位 - 第三个字符
[→ 统计1个维度,解析后续I得到int,拼接成int[],指针后移2位 - 第四个字符
[→ 统计2个维度,解析后续Z得到boolean,拼接成boolean[][],指针后移3位 - 参数解析完成,得到完整的参数类型列表
最后把类名、返回类型、方法名、参数列表拼接成可读格式即可。
关键注意点
- 数组类型要连续统计
[的数量,不能只处理单个维度 - 引用类型必须扫描到
;才结束,不能提前终止 - 基本类型是单个字符,直接匹配即可
内容的提问来源于stack exchange,提问作者zephyrus
相关产品推荐
相关产品推荐

