wdss的blog

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在产品中有时会遇到想动态调用java代码的时候,即在运行过程中,调用一段java代码字符串,经调研是可行的。代码如下:

 
import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.nio.file.Files.readAllBytes;
import static java.nio.file.Paths.get;


public class InlineCompiler {

    public static void main(String[] args) {
        String filename = "code.txt";
        String code = "";
        try {
            code = new String(readAllBytes(get(filename)));
        } catch (Exception e) {
        }
        System.out.println(code);
        String klassName = "GetMachineNo";
        String methodName = "execute";
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("machine_no", "a1b2");
        params.put("abc", "def");
        String result = getResult(code, klassName, methodName, params);
        System.out.println("result: " + result);
    }

    public static String getResult(String code, String klassName, String methodName, Map<String, Object> params) {

        try {

            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            //System.out.println("compiler: " + compiler);
            //StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
            ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));

            List<String> optionList = new ArrayList<String>();

            //Iterable<? extends JavaFileObject> compilationUnit = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(codeFile));
            List<JavaFileObject> jfiles = new ArrayList<>();
            jfiles.add(new CharSequenceJavaFileObject(klassName, code));
            JavaCompiler.CompilationTask task = compiler.getTask(
                    null,
                    fileManager,
                    diagnostics,
                    optionList,
                    null,
                    //compilationUnit);
                    jfiles);
            if (task.call()) {
                //URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("/tmp/javacode").toURI().toURL()});
                //Class<?> loadedClass = classLoader.loadClass(klassName);
                JavaClassObject jco = fileManager.getJavaClassObject();
                //DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.parentClassLoader);
                DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(Thread.currentThread().getContextClassLoader());
                Class<?> loadedClass = dynamicClassLoader.loadClass(klassName, jco);
                Object obj = loadedClass.newInstance();
                Method[] methods = loadedClass.getDeclaredMethods();
                Method callMethod = null;
                for (Method method : methods) {
                    if (method.getName().equals(methodName)) {
                        System.out.println("mn: " + method.getName());
                        callMethod = method;
                        break;
                    }
                }
                callMethod.setAccessible(true);
                String result = (String) callMethod.invoke(obj, params);

                return result;
            } else {
                for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                    System.out.format("Error on line %d in %s%n",
                            diagnostic.getLineNumber(),
                            diagnostic.getSource().toUri());
                }
            }
            fileManager.close();
        } catch (IOException | InstantiationException | IllegalAccessException | InvocationTargetException exp) {
            exp.printStackTrace();
        }
        return "";
    }
}


class ClassFileManager extends ForwardingJavaFileManager {
    private JavaClassObject jclassObject;

    public ClassFileManager(StandardJavaFileManager standardManager) {
        super(standardManager);
    }

    public JavaClassObject getJavaClassObject() {
        return jclassObject;
    }

    //需要覆盖
    @Override
    public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind,
                                               FileObject sibling) throws IOException {
        jclassObject = new JavaClassObject(className, kind);
        return jclassObject;
    }
}


class CharSequenceJavaFileObject extends SimpleJavaFileObject {

    private CharSequence code;

    public CharSequenceJavaFileObject(String className, CharSequence code) {
        super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}


class JavaClassObject extends SimpleJavaFileObject {

    private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    public JavaClassObject(String name, Kind kind) {
        super(URI.create("string:///" + name.replace('.', '/') + kind.extension), kind);
    }

    public byte[] getBytes() {
        return outputStream.toByteArray();
    }

    @Override
    public OutputStream openOutputStream() throws IOException {
        return outputStream;
    }
}


class DynamicClassLoader extends ClassLoader {
    public DynamicClassLoader(ClassLoader parent) {
        super(parent);
    }

    public Class loadClass(String fullName, JavaClassObject jco) {
        byte[] classData = jco.getBytes();
        return this.defineClass(fullName, classData, 0, classData.length);
    }
}


 

 

执行结果:


import java.util.Map;

public class GetMachineNo {
    
    public String execute(Map<String, Object> map) {
        try {
            return String.valueOf(map.get("machine_no")) + "_" + String.valueOf(map.get("abc"));
        } catch (Exception e) {
        }
        return "";
    }
}





mn: execute
result: a1b2_def

posted on 2021-10-29 15:17  wdss  阅读(750)  评论(0编辑  收藏  举报