Manupulating byte code generated from ASM
Asked Answered
M

2

6

I want to generate byte code for a java class only with the public or protected fields, constructors, and methods.

I am trying with the below code, but I don't know is it the correct approach?

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;
    }
}
Millican answered 19/6, 2020 at 6:58 Comment(1)
Looks good to me, Except that I would declare the first parameter of the constructor as ClassVisitor instead of ClassWriter.Giralda
M
1

Below code work for me

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
        }
    }
Millican answered 1/10, 2021 at 6:56 Comment(0)
D
0

Straight from the ASM FAQ at https://asm.ow2.io/faq.html#Q11

If you want to know how to generate a synchronized block, a try catch block, a finally statement, or any other Java construct, write the Java code you want to generate in a temporary class, compile it with javac, and then use the ASMifier to get the ASM code that will generate this class.

Depolarize answered 28/6, 2020 at 23:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.