【问题标题】:How do I re-encode dynamically compiled bytes to text?如何将动态编译的字节重新编码为文本?
【发布时间】:2014-06-13 12:13:47
【问题描述】:

考虑以下(Sourced primarily from here)

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

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

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

编辑: 是的,编译后的代码确实可以完美加载并运行。

【问题讨论】:

    标签: java dynamic character-encoding compilation


    【解决方案1】:

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

    如果没有看到所谓的“随机乱码”,我推测您看到的是类文件的格式良好的二进制内容,该文件已在某些字符集中“解码”为字符串。

    那是行不通的。它是一种二进制格式,你不能指望将它变成那样的文本并让它显示为可读的东西。

    (值得一提的是,“.class”文件不会包含 JVM 操作码的关键字,就像“.exe”文件会包含机器指令的关键字一样。它是 二进制强>!)


    如果您想以文本形式查看编译后的代码,则将该字节数组中的字节保存到一个文件中,然后使用javap 实用程序查看它。 (我会让你查找javap 命令的命令行语法...)

    【讨论】:

    • 啊哈,天哪,那是个大笨蛋。对不起。无论如何,在那种情况下,他们的编码是否有某种解码器?我可以在 Eclipse 中打开 .class 文件并列出操作码,所以它必须是可能的。
    猜你喜欢
    • 2019-07-01
    • 2018-01-31
    • 1970-01-01
    • 2014-01-20
    • 2012-07-11
    • 1970-01-01
    • 2021-02-15
    • 2021-04-24
    • 2019-01-06
    相关资源
    最近更新 更多