Search code examples
javabytecodejava-bytecode-asm

Manupulating byte code generated from ASM


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;
    }
}

Solution

  • 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
            }
        }