【发布时间】: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