GraalVM - Использование значения Polyglot без контекста
Я пишу приложение поверх Graal, которое сможет выполнять небольшие скрипты на разных языках.
Я пытаюсь написать некоторые модульные тесты для класса, который я использую для преобразования / обработки результата вызова Context.eval() (type: Value) в объект 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) также для извлечения значения Java из экземпляра значения Polyglot, чтобы я мог закрыть контекст. Другими словами, мне кажется, что прежде чем я смогу сделать Context.close(), мне нужно вызвать [value instance].asString() или.asWhwhat (), чтобы получить результат и иметь возможность закрыть контекст без получить IllegalStateException, как сказано в документации.
Я делаю это правильно? Есть ли лучший способ обработать получение результата и безопасно закрыть контекст?
Спасибо!
1 ответ
Как я могу протестировать мой класс 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. Например, значения полиглотов могут относиться ко всему графу объектов JavaScript.
Если возможно, я бы рекомендовал держать контекст открытым, пока нужны значения, так как он не требует каких-либо преобразований.
Если это невозможно и вы имеете дело только с примитивами и массивами, вы можете попробовать использовать следующий метод. Вы также можете попытаться скопировать объекты в землю Java, получив доступ к ее членам.
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 + ".");
}
Обратите внимание, что этот метод не всегда безопасен. Например, если массивы ссылаются на себя, этот метод завершится с ошибкой переполнения стека.