有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java ASM异常:执行可能会从代码create()V的末尾脱落

我正在尝试向使用ASM框架的类添加一个新方法public void create(){},但它会引发如下异常:

Exception in thread "main" java.lang.IllegalArgumentException: Execution can fall off the end of the code create()V

at org.objectweb.asm.util.CheckMethodAdapter$1.throwError(CheckMethodAdapter.java:474) at org.objectweb.asm.util.CheckMethodAdapter$1.visitEnd(CheckMethodAdapter.java:462) at org.objectweb.asm.MethodVisitor.visitEnd(MethodVisitor.java:783) at org.objectweb.asm.util.CheckMethodAdapter.visitEnd(CheckMethodAdapter.java:1036) at me.xx2bab.asmdemo.Weaver01AddRemoveFieldAndMethod$onProcess$classVisitor$1.visitEnd(Weaver01AddRemoveFieldAndMethod.kt:41) at org.objectweb.asm.ClassReader.accept(ClassReader.java:715) at org.objectweb.asm.ClassReader.accept(ClassReader.java:394)

以下是代码:

        val classReader = ClassReader(inputStream)
        val classWriter = ClassWriter(classReader, COMPUTE_FRAMES or COMPUTE_MAXS)
        val classVisitor = object : ClassVisitor(ASM9, CheckClassAdapter(classWriter, true)) {
            override fun visitEnd() {
//                visitField(
//                    Opcodes.ACC_PUBLIC,
//                    "newFieldName",
//                    "Ljava/lang/String;",
//                    null,
//                    null
//                ).visitEnd()
                visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "create",
                    "()V",
                    null,
                    null
                )?.visitEnd() // This is where exception throws
                super.visitEnd()
            }

        }
        classReader.accept(classVisitor, 0)

我试过在visitMethod前面移动super.visitEnd(),它会抛出“调用visitEnd后无法访问成员”然而,类似的操作也适用于visitField,就像我注释掉的代码片段一样

不确定实现这一要求的真正方式是什么


共 (1) 个答案

  1. # 1 楼答案

    根据@Holger来自comments的指示,我最终通过添加一个方法体解决了这个问题:

            // Add a new method
            val mv = classWriter.visitMethod(
                Opcodes.ACC_PUBLIC,
                "create",
                "()V",
                null,
                null
            )
            mv.visitFieldInsn(
                GETSTATIC,
                "java/lang/System",
                "out",
                "Ljava/io/PrintStream;"
            )
            mv.visitLdcInsn("this is add method print!")
            mv.visitMethodInsn(
                INVOKEVIRTUAL,
                "java/io/PrintStream",
                "println",
                "(Ljava/lang/String;)V",
                false
            )
            mv.visitInsn(RETURN)
            // this code uses a maximum of two stack elements and two local
            // variables
            mv.visitMaxs(0, 0)
            mv.visitEnd()
    
            return classWriter.toByteArray()