public class DynamicCompiler {
private static final DynamicCompiler DYNAMIC_COMPILER = new DynamicCompiler();
private DynamicCompiler() {
if (DYNAMIC_COMPILER != null) {
throw new AssertionError();
}
}
public static DynamicCompiler getInstance() {
return DYNAMIC_COMPILER;
}
public Object getJavaObject(String name, String code) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 错误监听信息
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
// 文件管理器,管理源代码和类文件,负责确定源代码和类文件的实例
ClassFileManager classFileManager = new ClassFileManager(
compiler.getStandardFileManager(diagnostics, null, null));
// Java源文件,可用于读取磁盘之外的数据,如,文本文件,字符串,数据库数据
JavaSourceFromString sourceFromString = new JavaSourceFromString(name, code);
JavaCompiler.CompilationTask task = compiler.getTask(
null, classFileManager, diagnostics, null, null, Arrays.asList(sourceFromString));
Boolean result = task.call();
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
throw new DynamicCompilerException(diagnostic.toString());
}
classFileManager.close();
if (result) {
ByteArrayClassFileObject javaFileObject = classFileManager.getByteArrayClassFileObject();
DynamicClassLoader dynamicClassLoader = new DynamicClassLoader();
Class<?> clazz = dynamicClassLoader.loadClass(name, javaFileObject);
try {
return clazz.newInstance();
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
}
return null;
}
}
/**
* 用于Java编程语言源和类文件的工具的文件管理器。
* 在这种情况下,文件意味着抽象普通文件和其他数据源。
*/
public class ClassFileManager extends ForwardingJavaFileManager {
public ClassFileManager(JavaFileManager fileManager) {
super(fileManager);
}
private ByteArrayClassFileObject byteArrayClassFileObject;
public ByteArrayClassFileObject getByteArrayClassFileObject() {
return byteArrayClassFileObject;
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
return byteArrayClassFileObject = new ByteArrayClassFileObject(className);
}
}
public class ByteArrayClassFileObject extends SimpleJavaFileObject {
private final ByteArrayOutputStream outputStream;
public ByteArrayClassFileObject(String name) {
super(URI.create("bytes:///" + name), Kind.CLASS);
outputStream = new ByteArrayOutputStream();
}
@Override
public OutputStream openOutputStream() throws IOException {
return outputStream;
}
public byte[] getBytes() {
return outputStream.toByteArray();
}
}
/**
* 该类提供了一个基本的文件对象实现,可以用作创建文件对象的构建块。
* 例如,这里是如何定义一个代表存储在一个字符串中的源代码的文件对象:
*/
public class JavaSourceFromString extends SimpleJavaFileObject {
private final CharSequence code;
public JavaSourceFromString(String name, CharSequence code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),
Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return code;
}
}
public class DynamicClassLoader extends ClassLoader {
public Class loadClass(String fullName, ByteArrayClassFileObject byteArrayClass) {
byte[] classData = byteArrayClass.getBytes();
return this.defineClass(fullName, classData, 0, classData.length);
}
}
public class DynamicCompilerException extends RuntimeException {
private String message;
public DynamicCompilerException(String message) {
super(message);
this.message = message;
}
public DynamicCompilerException(String message, Throwable cause) {
super(message, cause);
this.message = message;
}
@Override
public String getMessage() {
return message;
}
}
示例
读取文本文件JavaCompilerTest.txt
public class JavaCompilerTest {
public static void main(String[] args) {
System.out.println("JavaCompilerTest");
}
}
运行
@Test
public void dy() throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
DynamicCompiler dynamicCompiler = DynamicCompiler.getInstance();
byte[] data = Files.readAllBytes(Paths.get("JavaCompilerTest.txt"));
try {
Object o = dynamicCompiler.getJavaObject("JavaCompilerTest", new String(data, StandardCharsets.UTF_8));
Class clazz = o.getClass();
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, (Object) new String[]{});
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
网友评论