值提取系列
值提取系列
字串值提取工具-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);
}
}