22200

GraalVM - Using Polyglot Value without a context

I am writing an application ontop of Graal that will be able to execute small scripts in different languages.

I am trying to write some unit tests for a class I am using to convert/process the result of a Context.eval() call (type: Value) to a Java object. I know from the documentation that a Value instance is always bound to a Context, so when I try to write something like this:

@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); }

I get the following error:

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().

I guess that conceptually it does not make sense to have a "Value" instance without an associated bit of guest code, so my question is:

How can I go about testing my GuestLanguageResultProcessor class? Do I have to "bloat" my unit test with the creation of a context?

Side question for the experts: I am using this class (GuestLanguageResultProcessor) also to extract a Java value from the polyglot Value instance so that I can close the context. In other words it looks to me that before being able to do Context.close() I need to call [value instance].asString() or .asWhatever() in order to get the result out and being able to close the context without getting an IllegalStateException as it says in the docs.

Am I doing it right? Is there a better way to handle getting the result and closing the context safely?

Thank you!

Answer1:

How can I go about testing my GuestLanguageResultProcessor class? Do I have to "bloat" my unit test with the creation of a context?

I fear a bit of bloating is necessary. I'd recommend to use the following code to make your test work. This can also be done in a test base class, to avoid repetition.

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);
}



  

Am I doing it right? Is there a better way to handle getting the result and closing the context safely?

Value instances may be bound to guest language objects, like JavaScript objects which are invalid as soon as their context is closed. It is not always possible to convert guest language objects to a permanent Java representation. For example polyglot values might refer to an entire graph of JavaScript objects.

If possible, I would recommend to keep the context open as long as values are needed as it does not require any conversions.

If that is not possible and you are only dealing with primitives and Arrays you can try using the following method. You may also try to copy objects into Java land by accessing its members.

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 + ".");
}


Please note that this method is not always safe. For example if arrays refer to themselves, this method would crash with a stack-overflow error.

Recommend

  • NullPointerException while adding an object to an array
  • Getting p-values from leave-one-out in R
  • rabbitmq-erlang-client, using rebar friendly pkg, works on dev env fails on rebar release
  • How to convert string to table or objects in powershell
  • Vim syntax highlighting
  • In Ember.js, what's the difference between store save and store commit?
  • Why can't pass only 1 coulmn to glmnet when it is possible in glm function in R?
  • Matlab Generating a Matrix
  • EventEmitter in shared service's constructor doens't emit data
  • Error: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList
  • How can I get the maximum number of OpenMP threads that may be created during the whole execution of
  • Displaying pdf files using the PDFKit interface
  • NUnit 3.0 TestCase const custom object arguments
  • Elasticsearch script query involving root and nested values
  • Why use database factory in asp.net mvc?
  • How do I configure context broker accept post requests from my remote sensor?
  • What does 'Language neutral' mean with regard to MAKELANGID?
  • Android activity accessing service's static reference before the service is ready
  • PHP buffered output depending on server setting?
  • Switching to Release Build causes runtime error in Web Reference
  • OpenGL ES texture problem, 4 duplicate columns and horizontal lines (Android)
  • Display issues when we change from one jquery mobile page to another in firefox
  • Cross-Platform Protobuf Serialization
  • Javascript Callbacks with Object constructor
  • Trying to switch camera back to front but getting exception
  • Python - Map / Reduce - How do I read JSON specific field in using DISCO count words example
  • Hibernate gives error error as “Access to DialectResolutionInfo cannot be null when 'hibernate.
  • How to format a variable of double type
  • PHP: When would you need the self:: keyword?
  • Acquiring multiple attributes from .xml file in c#
  • Free memory of cv::Mat loaded using FileStorage API
  • Angular 2 constructor injection vs direct access
  • coudnt use logback because of log4j
  • Java static initializers and reflection
  • JaxB to read class hierarchy
  • Programmatically clearing map cache
  • reshape alternating columns in less time and using less memory
  • How can I use threading to 'tick' a timer to be accessed by other threads?