字符串值提取工具-04-java 调用 java? Janino 编译工具

值提取系列

值提取系列

字符串值提取工具-01-概览

字符串值提取工具-02-java 调用 js

字符串值提取工具-03-java 调用 groovy

字符串值提取工具-04-java 调用 java? Janino 编译工具

字符串值提取工具-05-java 调用 shell

字符串值提取工具-06-java 调用 python

字符串值提取工具-07-java 调用 go

代码地址

value-extraction 值提取核心

场景

我们希望通过 java 执行 java,如何实现呢?

入门例子

代码

package org.example;

import javax.tools.*;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

public class DynamicJavaExecutor {

    public static void main(String[] args) {
        // Java 代码字符串
        String javaCode =
                "public class HelloWorld { " +
                        "    public static void main(String[] args) { " +
                        "        System.out.println(\"Hello, World!\"); " +
                        "    } " +
                        "} ";

        // 编译 Java 代码
        boolean success = compileJavaCode("HelloWorld", javaCode);
        if (success) {
            try {
                // 使用 URLClassLoader 加载编译后的类
                File file = new File("./"); // 获取当前目录
                URL url = file.toURI().toURL(); // 转换为 URL
                URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
                Class<?> clazz = classLoader.loadClass("HelloWorld");

                // 调用类的 main 方法
                Method mainMethod = clazz.getMethod("main", String[].class);
                String[] params = null; // 传递给 main 方法的参数
                mainMethod.invoke(null, (Object) params);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("Compilation failed.");
        }
    }

    public static boolean compileJavaCode(String className, String javaCode) {
        // 创建自定义的 JavaFileObject
        JavaFileObject fileObject = new InMemoryJavaFileObject(className, javaCode);

        // 获取系统 Java 编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

        // 设置输出目录
        Iterable<String> options = Arrays.asList("-d", "./");

        // 编译 Java 代码
        JavaCompiler.CompilationTask task = compiler.getTask(
                null,
                fileManager,
                null,
                options,
                null,
                Arrays.asList(fileObject)
        );

        // 进行编译
        return task.call();
    }

    // 内部类,用于在内存中表示 Java 源文件
    static class InMemoryJavaFileObject extends SimpleJavaFileObject {
        private final String code;

        protected InMemoryJavaFileObject(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.code = code;
        }

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

测试效果:

Hello, World!

Janino 例子

maven 引入

<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
    <version>3.1.9</version>
</dependency>

代码

package org.example;

import org.codehaus.janino.SimpleCompiler;

public class JaninoExample {

    public static void main(String[] args) throws Exception {
        // Java 代码字符串
        String javaCode =
                "public class HelloWorld { " +
                        "    public void run() { " +
                        "        System.out.println(\"Hello, World!\"); " +
                        "    } " +
                        "} ";

        // 创建编译器实例
        SimpleCompiler compiler = new SimpleCompiler();

        // 编译 Java 代码
        compiler.cook(javaCode);

        // 获取编译后的类
        Class<?> clazz = compiler.getClassLoader().loadClass("HelloWorld");

        // 创建类的实例
        Object instance = clazz.getDeclaredConstructor().newInstance();

        // 调用 run 方法
        clazz.getMethod("run").invoke(instance);
    }

}

直接执行该方法

package com.github.houbb.value.extraction.test;

import org.codehaus.janino.ScriptEvaluator;

public class JavaDemoTest {

    public static void main(String[] args) throws Exception {
        // Java 脚本字符串
        String script =
                "System.out.println(\"Hello, World!\");";

        // 创建脚本求值器实例
        ScriptEvaluator scriptEvaluator = new ScriptEvaluator();

        // 编译并执行脚本
        scriptEvaluator.cook(script);
        scriptEvaluator.evaluate(null);
    }

}

传入参数,直接执行

package com.github.houbb.value.extraction.test;

import org.codehaus.janino.ScriptEvaluator;

import java.util.HashMap;
import java.util.Map;

public class JaninoExample {

    public static void main(String[] args) throws Exception {
        // 创建一个包含参数的 Map
        Map<String, Object> bindings = new HashMap<>();
        bindings.put("a", 10);
        bindings.put("b", 20);

        // 定义要执行的脚本
        String script = "System.out.println(\"Result: \" + (a + b));";

        // 调用方法来执行脚本
        executeScriptWithBindings(script, bindings);
    }

    public static void executeScriptWithBindings(String script, Map<String, Object> bindings) throws Exception {
        // 提取 Map 中的键(参数名)和值(参数值)
        String[] parameterNames = bindings.keySet().toArray(new String[0]);
        Class<?>[] parameterTypes = new Class<?>[parameterNames.length];

        // 假设所有参数的类型都是 Object,可以根据需要修改类型推断逻辑
        for (int i = 0; i < parameterNames.length; i++) {
            parameterTypes[i] = bindings.get(parameterNames[i]).getClass();
        }

        // 创建 ScriptEvaluator 实例
        ScriptEvaluator scriptEvaluator = new ScriptEvaluator();

        // 设置脚本的参数名称和类型
        scriptEvaluator.setParameters(parameterNames, parameterTypes);

        // 编译脚本
        scriptEvaluator.cook(script);

        // 提取 Map 中的值作为参数
        Object[] parameterValues = bindings.values().toArray();

        // 执行脚本
        scriptEvaluator.evaluate(parameterValues);
    }
}

但是感觉这个很麻烦,而且有问题

另一种执行的方式

package com.github.houbb.value.extraction.test.javas;

import org.codehaus.commons.compiler.CompileException;
import org.codehaus.janino.ScriptEvaluator;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class JaninoScriptMapExample {

    public static void main(String[] args) throws CompileException, InvocationTargetException {
        // 示例脚本,使用 Map 参数
        String script =
                "return map.get(\"greeting\") + \", \" + map.get(\"name\") + \"!\";";

        // 创建 ScriptEvaluator 实例,指定返回类型、参数名和参数类型
        ScriptEvaluator se = new ScriptEvaluator(
                script,                      // 脚本代码
                Object.class,                // 返回值类型
                new String[]{"map"},         // 参数名列表
                new Class<?>[]{Map.class}    // 参数类型列表
        );

        // 准备传入的 Map 参数
        Map<String, Object> params = new HashMap<>();
        params.put("greeting", "Hello");
        params.put("name", "Janino");

        // 执行脚本,传入 Map 参数
        Object result = se.evaluate(new Object[]{params});

        // 输出结果
        System.out.println(result);
    }

}

热门相关:强宠头号鲜妻:陆少,滚!   血战天下   医道至尊   恶魔总裁霸道宠:老婆,太惹火   我的女友是丧尸