ClassMetaReader.build() 中获取变量名的那部分代码原本是按照本地变量表字节码的写入顺序获取变量名的,但由于在写入本地变量表的时候,形参与局部变量写入的顺序是不可控的,所以导致会导致后续按形参的下标获取对应的形参名称时会出现错乱,故建议按本地变量表的Slot属性升序排列。调整如下:
if ("LocalVariableTable".equals(codeAttrName)) {//形参在LocalVariableTable属性中
int local_variable_table_length = dis.readUnsignedShort();
//按本地变量表的Slot属性升序排列,保证形参名称的下标与所对应参数的下标一致
TreeMap<Integer, String> varSlotNameMap = new TreeMap<Integer, String>();
for (int l = 0; l < local_variable_table_length; l++) {
dis.skipBytes(2);
dis.skipBytes(2);
String varName = strs.get(dis.readUnsignedShort());
dis.skipBytes(2);
int varSlot = dis.readUnsignedShort();//这是变量的下标
if (!"this".equals(varName)) //非静态方法,第一个参数是this
varSlotNameMap.put(varSlot, varName);//varNames.add(varName);
}
List<String> varNames = new ArrayList<String>(varSlotNameMap.values());
if (!names.containsKey(key))
names.put(key, varNames);
}
另附上部分反编译后的字节码信息(局部变量在形参之前写入本地变量表):
public com.xxx.xxx.transport.Response saveContent(java.lang.String, com.xxx.xxx.nutz.entity.config.NutzContent, org.nutz.plugins.validation.Errors);
...
LocalVariableTable:
Start Length Slot Name Signature
114 55 9 definition Lcom/xxx/xxx/entity/config/Definition;
92 80 8 i$ Ljava/util/Iterator;
58 126 5 definitions Ljava/util/List;
80 104 6 contentMap Ljava/util/Map;
83 101 7 msg Ljava/lang/String;
0 216 0 this Lcom/xxx/xxx/nutz/module/ConfigModule;
0 216 1 path Ljava/lang/String;
0 216 2 content Lcom/xxx/xxx/nutz/entity/config/NutzContent;
0 216 3 errors Lorg/nutz/plugins/validation/Errors;
30 186 4 response Lcom/xxx/xxx/transport/Response;