使用ASM字节码生成编解码器时遇类方法找不到问题求助
问题排查与解决方案
核心原因:泛型类型擦除导致方法签名不匹配
你的Patchable<T>是泛型类,Java编译时会执行类型擦除:泛型参数T会被替换为上限类型(此处为Object),因此编译后的Patchable类中,getPayload()方法的实际签名是:
public Object getPayload()
但ASM生成的字节码里直接调用了签名为()Ljava/lang/String;的getPayload()方法:
INVOKEVIRTUAL com/cinnober/msgcodec/Patchable.getPayload ()Ljava/lang/String;
JVM加载生成的Codec类时,会在Patchable类中查找该签名的方法,而实际类中只有()Ljava/lang/Object;版本的方法,因此抛出NoSuchMethodError。
CHECKCAST指令仅验证对象是Patchable实例,和方法签名是否匹配无关。
修复方案
调整ASM生成的字节码逻辑,先调用泛型擦除后的getPayload()(返回Object),再做类型转换到目标类型,最后调用写入方法:
修改后的ASM指令序列:
ALOAD 1 ALOAD 0 GETFIELD com/cinnober/msgcodec/blink/GeneratedBlinkCodec0.accessor_PatchableEntity_patchable : Lcom/cinnober/msgcodec/Accessor; ALOAD 2 INVOKEINTERFACE com/cinnober/msgcodec/Accessor.getValue (Ljava/lang/Object;)Ljava/lang/Object; (itf) CHECKCAST com/cinnober/msgcodec/Patchable INVOKEVIRTUAL com/cinnober/msgcodec/Patchable.getPayload ()Ljava/lang/Object; CHECKCAST java/lang/String INVOKESTATIC com/cinnober/msgcodec/blink/BlinkOutput.writeStringUTF8Null (Lcom/cinnober/msgcodec/io/ByteSink;Ljava/lang/String;)V RETURN
关键修改点
- 将
INVOKEVIRTUAL的方法签名从()Ljava/lang/String;改为()Ljava/lang/Object;,匹配泛型擦除后的实际方法 - 添加
CHECKCAST java/lang/String指令,将返回的Object转换为String类型,适配后续写入方法的参数要求
额外验证建议
- 执行
javap -c com.cinnober.msgcodec.Patchable命令查看编译后的Patchable类字节码,确认getPayload()的实际签名,验证上述结论 - 若后续支持其他类型的
Patchable<T>,只需将CHECKCAST的类型替换为对应类型即可,保持逻辑一致性
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

