Java 内存动态编译执行

2021-03-28  本文已影响0人  taogan
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());
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读