java - 如何将动态编译的字节重新编码为文本?

标签 java dynamic character-encoding compilation

考虑以下(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 足够简单,但出于性能目的,我需要能够使用这个缓存示例(当然没有可能的内存泄漏)。

编辑: 是的,编译后的代码可以完美地进行类加载和运行。

最佳答案

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?

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

那是行不通的。它是一种二进制格式,您不能期望将其转换为这样的文本并使其显示为可读的内容。

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

<小时/>

如果您想以文本形式查看编译后的代码,请将字节数组中的字节保存到文件中,并使用 javap实用看看吧。 (我将让您查找 javap 命令的命令行语法...)

关于java - 如何将动态编译的字节重新编码为文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23332788/

相关文章:

java - Windows Bat 文件无法使用德语元音变音

html - 检测 HTML 中的字符编码

java - 无法使用 kerberos 票证缓存对 apache http 客户端 4.5 进行身份验证

dynamic - 如何动态更新 OSGi 包?

c# - 类型 'Contains' 1[System.Object] 上不存在方法 'System.Data.Linq.DataQuery`

android - iOS 和 Android 应用动态 UI 所需的技术推荐

c# - HttpClient 抛出 System.ArgumentException : 'windows-1251' is not a supported encoding name

java - 在 Spring MVC 中使用 JSR 303 注释仅检查空格的更好方法

java - 使用Java解析多个双引号文件名

java - 在 Java 中使用 JSON API