You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:35:01