All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zodiac.script.engine.java.DynamicCompilerEngine Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.script.engine.java;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.List;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.Strings;

public class DynamicCompilerEngine {

    private static final Logger logger = LoggerFactory.getLogger(DynamicCompilerEngine.class);

    private ClassLoader parentClassLoader;
    private String classpath;

    private DynamicCompilerEngine() {
        // 获取类加载器
        this.parentClassLoader = this.getClass().getClassLoader();
        // 创建classpath
        try {
            this.buildClassPath();
        } catch (IOException e) {
            logger.error("建立ClassPath错误",e);
        }
    }

    private void buildClassPath() throws IOException {
        this.classpath = null;
        if (this.parentClassLoader instanceof URLClassLoader) {
            
            ClassLoader cl = parentClassLoader;
            List paths = Colls.list();
            while (cl instanceof URLClassLoader) {
                for (URL url : ((URLClassLoader) cl).getURLs()) {
                    if (url.openConnection() instanceof JarURLConnection) {
                        // extract the file URL from the jar URL
                        JarURLConnection connection = (JarURLConnection) url.openConnection();
                        url = connection.getJarFileURL();
                    }
                    String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8");
                    paths.add(new File(decodedPath).getAbsolutePath());
                }
                cl = cl.getParent();
            }
            StringBuilder sb = new StringBuilder();
            for (String path : paths) {
                if(Strings.isNoneBlank(path)) {
                    sb.append(path).append(File.pathSeparator);
                }
            }
            this.classpath = sb.toString();
        } else {
            this.classpath = System.getProperty("java.class.path");
        }
    }

    public Class javaCodeToClass(String fullClassName, String javaCode, String classPath) throws IllegalAccessException, InstantiationException {
        // 获取系统编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 建立DiagnosticCollector对象
        DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>();

        // 建立用于保存被编译文件名的对象
        // 每个文件被保存在一个从JavaFileObject继承的类中
        ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnosticCollector, null, null));

        List jfiles = Colls.list();
        jfiles.add(new CharSequenceJavaFileObject(fullClassName, javaCode));

        // 使用编译选项可以改变默认编译行为。编译选项是一个元素为String类型的Iterable集合
        List options = Colls.list();
        options.add("-encoding");
        options.add("UTF-8");
        options.add("-classpath");
        if(Strings.blank(classPath)) {
            options.add(this.classpath);
        }else {
            options.add(this.classpath+File.pathSeparator+classPath+File.pathSeparator);
        }
        // 不使用SharedNameTable (jdk1.7自带的软引用,会影响GC的回收,jdk1.9已经解决)
        options.add("-XDuseUnsharedTable");

        JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, fileManager, diagnosticCollector, options, null, jfiles);

        // 编译源程序
        boolean success = compilationTask.call();

        if (success) {
            // 如果编译成功,用类加载器加载该类
            JavaClassObject jco = fileManager.getJavaClassObject();
            DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.parentClassLoader);
            Class clazz = dynamicClassLoader.loadClass(fullClassName, jco);
            try {
                dynamicClassLoader.close();
            } catch (IOException e) {
                logger.error("关闭动态类加载器错误", e);
            }
            return clazz;
        } else {
            // 如果想得到具体的编译错误,可以对Diagnostics进行扫描
            for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) {
                String error = compilePrint(diagnostic);
                logger.error("编译错误,\n" + error);
            }
            return null;
        }
    }

    /**
     * @param diagnostic diagnostic
     * @return result
     */
    private String compilePrint(Diagnostic diagnostic) {
        System.out.println("Code:" + diagnostic.getCode());
        System.out.println("Kind:" + diagnostic.getKind());
        System.out.println("Position:" + diagnostic.getPosition());
        System.out.println("Start Position:" + diagnostic.getStartPosition());
        System.out.println("End Position:" + diagnostic.getEndPosition());
        System.out.println("Source:" + diagnostic.getSource());
        System.out.println("Message:" + diagnostic.getMessage(null));
        System.out.println("LineNumber:" + diagnostic.getLineNumber());
        System.out.println("ColumnNumber:" + diagnostic.getColumnNumber());
        StringBuffer res = new StringBuffer();
        res.append("Code:[" + diagnostic.getCode() + "]\n");
        res.append("Kind:[" + diagnostic.getKind() + "]\n");
        res.append("Position:[" + diagnostic.getPosition() + "]\n");
        res.append("Start Position:[" + diagnostic.getStartPosition() + "]\n");
        res.append("End Position:[" + diagnostic.getEndPosition() + "]\n");
        res.append("Source:[" + diagnostic.getSource() + "]\n");
        res.append("Message:[" + diagnostic.getMessage(null) + "]\n");
        res.append("LineNumber:[" + diagnostic.getLineNumber() + "]\n");
        res.append("ColumnNumber:[" + diagnostic.getColumnNumber() + "]\n");
        return res.toString();
    }

    public static DynamicCompilerEngine getInstance() {
        return DynamicCompilerEngineHolder.INSTANCE;
    }

    private static class DynamicCompilerEngineHolder {
        private static final DynamicCompilerEngine INSTANCE = new DynamicCompilerEngine();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy