字符串值提取工具-04-java 调用 java? Janino 编译工具
值提取系列
值提取系列
字符串值提取工具-04-java 调用 java? Janino 编译工具
代码地址
场景
我们希望通过 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);
}
}