java - 操作从 ASM 生成的字节码

标签 java bytecode java-bytecode-asm

我只想为带有公共(public)或 protected 字段、构造函数和方法的 java 类生成字节码。

我正在尝试使用以下代码,但我不知道 这是正确的方法吗?

Client code:


String sourceFileName = file.getName();
ClassReader reader = new ClassReader(file.getContents());
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
reader.accept(adapter, 0);
byte[] content = writer.toByteArray();
// we can use content to print in .class file

Adapator code:


private class JavaStubClassAdapter extends ClassVisitor {
    private final String sourceFileName;

    /**
     * @param writer
     * @param sourceFileName
     */
    public JavaStubClassAdapter(ClassWriter writer, String sourceFileName) {
        super(Opcodes.ASM7, writer);
        this.sourceFileName = sourceFileName;
    }

    @Override
    public void visitSource(String source, String debug) {
        super.visitSource(this.sourceFileName, null);
    }

    @Override
    public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
        if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
            return super.visitField(access, name, descriptor, signature, value);
        }
        return null;
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
            String[] exceptions) {
        if (access == Opcodes.ACC_PUBLIC || access == Opcodes.ACC_PROTECTED) {
            return super.visitMethod(access, name, descriptor, signature, exceptions);
        }
        return null;
    }
}

最佳答案

下面的代码对我有用

Client code this method has org.eclipse.core.resources.IFile

        ClassReader reader = new ClassReader(file.getContents());
        if (!isAccessPermited(reader.getAccess())) {
            return new byte[0];
        }
        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        JavaStubClassAdapter adapter = new JavaStubClassAdapter(writer, sourceFileName);
        reader.accept(adapter, 0);
        return writer.toByteArray();

Helper methods

    private static boolean isAccessPermited(final int access) {
        boolean isEnumAcc = (access & Opcodes.ACC_ENUM) == 0 ? false : true;
        boolean isPublicAcc = (access & Opcodes.ACC_PUBLIC) == 0 ? false : true;
        boolean  isProtectedAcc = (access & Opcodes.ACC_PROTECTED) == 0 ? false : true;
        if (isPublicAcc || isProtectedAcc || isEnumAcc) {
            return true;
        }
        return false;
    }

    private static boolean isFinalAccess(final int access) {
        return (access & Opcodes.ACC_FINAL) != 0;
    }

Adapator code

    private static class JavaStubClassAdapter extends ClassVisitor {
        private final String sourceFileName;

        /**
         * @param writer
         *            ClassVisitor
         * @param sourceFileName
         *            String
         */
        public JavaStubClassAdapter(ClassVisitor writer, String sourceFileName) {
            super(Opcodes.ASM7, writer);
            this.sourceFileName = sourceFileName;
        }

        @Override
        public void visitSource(String source, String debug) {
            super.visitSource(this.sourceFileName, null);
        }

        @Override
        public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
            if (isAccessPermited(access)) {
                switch (descriptor) {
                case "Ljava/lang/String;":  //$NON-NLS-1$
                    if (isFinalAccess(access)) {
                        return super.visitField(access, name, descriptor, signature, "");
                    }
                    return super.visitField(access, name, descriptor, signature, null);
                case "Z":                   //$NON-NLS-1$
                    return super.visitField(access, name, descriptor, signature, Boolean.FALSE);
                case "C":                   //$NON-NLS-1$
                case "B":                   //$NON-NLS-1$
                case "S":                   //$NON-NLS-1$
                case "I":                   //$NON-NLS-1$
                case "J":                   //$NON-NLS-1$
                case "D":                   //$NON-NLS-1$
                case "F":                   //$NON-NLS-1$
                    if (isFinalAccess(access)) {
                        return super.visitField(access, name, descriptor, signature, Integer.valueOf(0));
                    }
                    return super.visitField(access, name, descriptor, signature, null);
                case "Ljava/lang/Object":   //$NON-NLS-1$
                    return super.visitField(access, name, descriptor, signature, null);

                default:
                    return super.visitField(access, name, descriptor, signature, null);
                }
            }
            return null;
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
                String[] exceptions) {
            if (isAccessPermited(access)) {
                MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
                return new JavaClassEmptyMethodVistor(mv, Type.getReturnType(descriptor));
            }
            return null;
        }

        @Override
        public void visitInnerClass(String name, String outerName, String innerName, int access) {
            if (isAccessPermited(access)) {
                super.visitInnerClass(name, outerName, innerName, access);
            }
        }
    }
    
    private static class JavaClassEmptyMethodVistor extends MethodVisitor {
        private final MethodVisitor visitor;

        private final Type returnType;

        public JavaClassEmptyMethodVistor(MethodVisitor methodVisitor, Type type) {
            super(Opcodes.ASM7, methodVisitor);
            this.visitor = methodVisitor;
            this.returnType = type;
        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
            // Do nothing
        }

        @Override
        public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
            // Do nothing
        }

        @Override
        public void visitInsn(int opcode) {
            if (returnType == Type.INT_TYPE || returnType == Type.FLOAT_TYPE
                    || returnType == Type.LONG_TYPE || returnType == Type.DOUBLE_TYPE
                    || returnType == Type.CHAR_TYPE || returnType == Type.BYTE_TYPE ) {
                visitor.visitIntInsn(Opcodes.BIPUSH, 0);
                visitor.visitInsn(Opcodes.IRETURN);
            } else if (returnType == Type.BOOLEAN_TYPE) {
                visitor.visitInsn(Opcodes.ICONST_0);
                visitor.visitInsn(Opcodes.IRETURN);
            } else if (returnType == Type.VOID_TYPE) {
                visitor.visitInsn(Opcodes.RETURN);
            } else {
                visitor.visitInsn(Opcodes.ACONST_NULL);
                visitor.visitInsn(Opcodes.ARETURN);
            }
        }

        @Override
        public void visitIincInsn(int var, int increment) {
            // Do nothing
        }

        @Override
        public void visitLineNumber(int line, Label start) {
            // Do nothing
        }

        @Override
        public void visitLabel(Label label) {
            // Do nothing
        }

        @Override
        public void visitTypeInsn(int opcode, String type) {
            // Do nothing
        }

        @Override
        public void visitJumpInsn(int opcode, Label label) {
            // Do nothing
        }

        @Override
        public void visitLdcInsn(Object value) {
            // Do nothing
        }

        @Override
        public void visitVarInsn(int opcode, int var) {
            // Do nothing
        }

        @Override
        public void visitMaxs(int maxStack, int maxLocals) {
            visitor.visitMaxs(0, 0);
        }

        @Override
        public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
            // Do nothing
        }

        @Override
        public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
            // Do nothing
        }

        @Override
        public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
            // Do nothing
        }

        @Override
        public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
            // Do nothing
        }
    }

关于java - 操作从 ASM 生成的字节码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62464896/

相关文章:

java - Android:如何以编程方式为 fragment 设置边距?

java - 在 Java/C# 中设置/获取系统时间

java - 我将如何解析 Java 类文件常量池?

java - 如何以编程方式确定当前类的 Java 字节码版本?

java - 生成没有默认构造函数的类的子类

java - 是否有类似的 VisitLdcInsn 用于加载对象(不是常量)?

java - Spring数据聚合查询elasticsearch

java - 使用 Java 通过 SSL 的 LDAP

java - 字节好友代码生成

java - Jasmin 中的汇编语言 - 出现语法错误