如何配置GraalVM Polyglot使Java类可被Python脚本导入
从Jython迁移至GraalVM Polyglot:Java类无法被Python脚本导入的问题解决
问题背景
需要将Java项目中的Python脚本执行逻辑从Jython迁移到GraalVM Polyglot,但遇到Java类无法被Python脚本导入的问题——相同脚本在Jython环境可正常运行,在GraalVM Python环境下无法工作。
初始测试代码与依赖
JUnit测试类
package org.my.graalvm.python.issue; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleBindings; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Source; import org.junit.jupiter.api.Test; public class GraalVmPythonTests { static final String SCRIPT = """ import org.my.graalvm.python.issue.GraalVmPythonTests.MyData as MyData result=MyData('some data') """; @Test void runPythonScriptWithJavaImportOnJython() throws ScriptException { ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("python"); Bindings bindings = new SimpleBindings(); scriptEngine.eval(SCRIPT, bindings); System.out.println(bindings.get("result")); } @Test void runPythonScriptWithJavaImportOnGraalVmPolyglot() { try (Context context = Context.newBuilder().allowAllAccess(true).build()) { Source source = Source.create("python", SCRIPT); Object result = context.eval(source).as(Object.class); System.out.println(result); } } public record MyData(String value) { } }
项目依赖(Gradle)
dependencies { testImplementation 'org.python:jython-standalone:2.7.4' testImplementation 'org.graalvm.sdk:graal-sdk:24.0.2' testImplementation 'org.graalvm.polyglot:python:24.0.2' testImplementation 'org.junit.jupiter:junit-jupiter:5.11.1' }
尝试过程与问题排查
根据GraalVM官方文档,可使用--python.EmulateJython参数,但希望找到无需依赖Jython的原生Polyglot配置方式。
第一次尝试:使用java.type导入Java类
调整Python脚本为:
import java MyData = java.type("org.my.graalvm.python.issue.GraalVmPythonTests.MyData") result = MyData("some data")
对应的测试代码修改为:
@Test void runPythonScriptWithJavaImportOnGraalVmPolyglot() { Context.Builder contextBuilder = Context.newBuilder("python") .allowAllAccess(true) .hostClassLoader(getClass().getClassLoader()); try (Context context = contextBuilder.build()) { Source source = Source.create("python", SCRIPT); Object result = context.eval(source).as(Object.class); System.out.println(result); } }
执行后报错:
KeyError: host symbol org.my.graalvm.python.issue.GraalVmPythonTests.MyData is not defined or access has been denied at <python> <module>(Unknown) at org.graalvm.polyglot.Context.eval(Context.java:402) at org.my.graalvm.python.issue.GraalVmPythonTests.runPythonScriptWithJavaImportOnGraalVmPolyglot(GraalVmPythonTests.java:40)
可行方案1:启用python.EmulateJython参数
添加该参数到Context配置,并修改Python脚本为Jython风格的导入:
Python脚本:
from org.my.graalvm.python.issue.GraalVmPythonTests import MyData result = MyData('some data')
测试代码:
@Test void runPythonScriptWithJavaImportOnGraalVmPolyglot() { Context.Builder contextBuilder = Context.newBuilder() .allowAllAccess(true) .option("python.EmulateJython", "true"); try (Context context = contextBuilder.build()) { Source source = Source.create("python", SCRIPT); Object result = context.eval(source).as(Object.class); System.out.println(((Map<?, ?>) result).get("result")); } }
此配置下脚本可正常运行,但依赖Jython兼容模式。
无需Jython兼容的最终方案(处理内部类)
发现内部类无法通过直接导入的方式解析,最终找到无需Jython兼容的可行方式:
测试类代码
package org.my.graalvm.python.issue; import java.util.Map; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Source; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertInstanceOf; public class GraalVmPythonTests { static final String SCRIPT = """ import java GraalVmPythonTests = java.type("org.my.graalvm.python.issue.GraalVmPythonTests") result = GraalVmPythonTests.MyData('some data') """; @Test void runPythonScriptWithJavaImportOnGraalVmPolyglot() { Context.Builder contextBuilder = Context.newBuilder() .allowAllAccess(true); try (Context context = contextBuilder.build()) { Source source = Source.create("python", SCRIPT); Object result = context.eval(source).as(Object.class); assertInstanceOf(MyData.class, (((Map<?, ?>) result).get("result"))); } } public record MyData(String value) { } }
此方案通过先获取外部类,再访问内部类的方式,在原生GraalVM Python环境下成功导入并实例化Java内部类。
内容的提问来源于stack exchange,提问作者Artem Bilan
相关产品推荐
相关产品推荐

