如何将动态编译的字节重新编码为文本? [英] How do I re-encode dynamically compiled bytes to text?

查看:121
本文介绍了如何将动态编译的字节重新编码为文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下(主要来自此处)

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler( );
JavaFileManager manager = new MemoryFileManager( compiler.getStandardFileManager( null, null, null ) );

compiler.getTask( null, manager, null, null, null, sourceScripts ).call( ); //sourceScripts is of type List<ClassFile>

以下文件管理器:

public class MemoryFileManager extends ForwardingJavaFileManager< JavaFileManager > {
    private HashMap< String, ClassFile > classes = new HashMap<>( );

    public MemoryFileManager( StandardJavaFileManager standardManager ) {
        super( standardManager );
    }

    @Override
    public ClassLoader getClassLoader( Location location ) {
        return new SecureClassLoader( ) {
            @Override
            protected Class< ? > findClass( String className ) throws ClassNotFoundException {
                if ( classes.containsKey( className ) ) {
                    byte[ ] classFile = classes.get( className ).getClassBytes( );
                    System.out.println(new String(classFile, "utf-8"));
                    return super.defineClass( className, classFile, 0, classFile.length );
                } else throw new ClassNotFoundException( );
            }
        };
    }

    @Override
    public ClassFile getJavaFileForOutput( Location location, String className, Kind kind, FileObject sibling ) {
        if ( classes.containsKey( className ) ) return classes.get( className );
        else {
            ClassFile classObject = new ClassFile( className, kind );
            classes.put( className, classObject );
            return classObject;
        }
    }
}

public class ClassFile extends SimpleJavaFileObject {
    private byte[ ] source;
    protected final ByteArrayOutputStream compiled = new ByteArrayOutputStream( );

    public ClassFile( String className, byte[ ] contentBytes ) {
        super( URI.create( "string:///" + className.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE );
        source = contentBytes;
    }

    public ClassFile( String className, CharSequence contentCharSequence ) throws UnsupportedEncodingException {
        super( URI.create( "string:///" + className.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE );
        source = ( ( String )contentCharSequence ).getBytes( "UTF-8" );
    }

    public ClassFile( String className, Kind kind ) {
        super( URI.create( "string:///" + className.replace( '.', '/' ) + kind.extension ), kind );
    }

    public byte[ ] getClassBytes( ) {
        return compiled.toByteArray( );
    }

    public byte[ ] getSourceBytes( ) {
        return source;
    }

    @Override
    public CharSequence getCharContent( boolean ignoreEncodingErrors ) throws UnsupportedEncodingException {
        return new String( source, "UTF-8" );
    }

    @Override
    public OutputStream openOutputStream( ) {
        return compiled;
    }
}

在编译器上执行代码, ).call(),这里发生的第一件事是调用getJavaFileForOutput(),然后调用getClassLoader()方法来加载类,这会在编译的字节中产生写入控制台。

Stepping through the code, on the compiler.getTask().call(), the first thing that happens here is getJavaFileForOutput() is called, and then the getClassLoader() method is called to load the class, which yields in the compiled bytes being written to console.

为什么getClassLoader()方法中的println产生了我工作的编译字节码的合并(主要是字符串,似乎实际的字节码指令关键字不在这里)和随机乱码?这使我相信我使用的UTF太短,所以我尝试UTF-16,它看起来或多或少相似。如何将字节编码回文本?我知道使用SimpleJavaFileManager会很简单,但是我需要使用这个缓存示例(当然没有可能的内存泄漏)。

Why does that println in the getClassLoader() method yield an amalgamation of my working compiled bytecode(primarily strings, it appears the actual bytecode instruction keywords are not here) and random gibberish? This leads me to believe that I was using too short a UTF so I tried UTF-16, and it looked more or less similar. How do I encode the bytes back into text? I am aware that using the SimpleJavaFileManager would be straightforward enough but I need to be able to use this example of caching(without the possible memory leaks of course) for performance purposes.

编辑:
是的,编译的代码执行类加载和运行完美。

And yes, the compiled code does classload and run perfectly.

推荐答案


为什么getClassLoader()方法中的println产生了我工作的编译字节码的合并(主要是字符串,似乎实际的字节码指令关键字不在这里)和随机乱码?

Why does that println in the getClassLoader() method yield an amalgamation of my working compiled bytecode(primarily strings, it appears the actual bytecode instruction keywords are not here) and random gibberish?

没有看到所谓的随机乱码,我猜想你所看到的是一个已被解码为一个字符串的类文件的格式良好的二进制内容在某些字符集。

Without seeing the so-called "random gibberish", I would surmise that what you are seeing is the well-formed binary content of a class file that has been "decoded" as a String in some character set.

这不会工作。它是一种二进制格式,您不能期望将其转换为文本,并将其显示为可读的东西。

That ain't going to work. It is a binary format, and you can't expect to turn it into text like that and have it display as something readable.

(为什么值得,.class文件不包含JVM操作码的关键字,只有.exe文件将包含关键字对于机器指令,它是二进制!)

(And for what it is worth, a ".class" file would not contain keywords for the JVM opcodes, any more than a ".exe" file would contain keywords for machine instructions. It is binary!)

如果要查看编译代码在文本格式中,然后将该字节数组中的字节保存到文件中,并使用 javap 实用程序来查看它。 (我会让你查找 javap 命令的命令行语法...)

If you want to see the compiled code in text form, then save the bytes in that byte array to a file, and use the javap utility to look at it. (I'll leave you to look up the command line syntax for the javap command ... )

这篇关于如何将动态编译的字节重新编码为文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆