GraalVM-在没有上下文的情况下使用Polyglot值

时间:2018-08-03 09:10:32

标签: graalvm

我正在Graal之上编写一个应用程序,该应用程序将能够执行不同语言的小脚本。

我正在尝试为用于将Context.eval()调用(类型:值)的结果转换/处理为Java对象的类编写一些单元测试。我从文档中知道Value实例始终绑定到Context,因此当我尝试编写如下内容时:

@Test
public void NumericFloatTest() throws ScriptExecutionException {

    GuestLanguageResultProcessor LangProcessor = new GuestLanguageResultProcessor();
    Float javaValue = (float) 43.25;
    Value numValue = Value.asValue(javaValue);
    LangProcessor.processResult(numValue);

    Object result = LangProcessor.processResult(numValue);

    assertThat(result.getClass()).isEqualTo(Float.class);
}

我收到以下错误:

java.lang.IllegalStateException: No current context is available. Make sure the Java method is invoked by a Graal guest language or a context is entered using Context.enter().

我想从概念上讲,没有关联的来宾代码就没有“ Value”实例是没有意义的,所以我的问题是:

如何测试我的GuestLanguageResultProcessor类?创建上下文时,我是否必须“膨胀”单元测试?

专家的附加问题:我也使用此类(GuestLanguageResultProcessor)从多语言Value实例中提取Java值,以便关闭上下文。换句话说,在我看来,在能够执行Context.close()之前,我需要调用[值实例] .asString()或.asWhatever()以便获得结果并能够关闭上下文而无需按照docs中的说明获取IllegalStateException。

我做对了吗?有没有更好的方法来处理结果并安全地关闭上下文?

谢谢!

1 个答案:

答案 0 :(得分:4)

  

如何测试我的GuestLanguageResultProcessor类?我必须通过创建上下文来“膨胀”我的单元测试吗?

我担心有点胀气是必要的。我建议使用以下代码来进行测试。也可以在测试基类中完成此操作,以避免重复。

Context context;

@Before
public void setup() {
    context = Context.create();
    context.enter();
}

@After
public void setup() {
    context.leave();
    context.close();
}

@Test
public void NumericFloatTest() throws ScriptExecutionException {
    GuestLanguageResultProcessor LangProcessor = new GuestLanguageResultProcessor();
    Float javaValue = (float) 43.25;
    Value numValue = Value.asValue(javaValue);
    LangProcessor.processResult(numValue);

    Object result = LangProcessor.processResult(numValue);

    assertThat(result.getClass()).isEqualTo(Float.class);
}
  

我做对了吗?有没有更好的方法来处理结果并安全地关闭上下文?

值实例可以绑定到来宾语言对象,例如JavaScript对象,一旦上下文关闭,它们就无效。并非总是可能将来宾语言对象转换为永久Java表示形式。例如,polyglot值可能引用JavaScript对象的整个图。

如果可能的话,我建议保持上下文开放,只要需要值就可以,因为它不需要任何转换。

如果这是不可能的,并且您仅处理基元和数组,则可以尝试使用以下方法。您也可以尝试通过访问其成员将对象复制到Java Land。

Object copyToJavaLand(Value value) {
    if (value.isBoolean()) {
        return value.asBoolean();
    } else if (value.isString()) {
        return value.asString();
    } else if (value.isNumber()) {
        return value.as(Number.class);
    } else if (value.isHostObject()) {
        return value.asHostObject();
    } else if (value.isProxyObject()) {
        return value.asProxyObject();
    } else if (value.hasArrayElements()) {
        Object[] array = new Object[(int) value.getArraySize()];
        for (int i = 0; i < array.length; i++) {
            array[i] = copyToJavaLand(value.getArrayElement(i));
        }
        return array;
    }
    throw new IllegalArgumentException("Cannot copy value " + value + ".");
}

请注意,此方法并不总是安全的。例如,如果数组引用自身,则此方法将崩溃并出现堆栈溢出错误。