Script expression error switching from JDK11 to JDK17

Hi folks,

we are running preparations to upgrade our 7.18 to 7.20 (and JDK 11 to JDK17 and Spring Boot 2.x to Spring Boot 3.x).

Currently, we just modified the version of JDK from 11 to 17 and added Graal VM JS Scripting Engine to the classpath.

<properties>
    <graalvm.version>22.3.3</graalvm.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.graalvm.sdk</groupId>
        <artifactId>graal-sdk</artifactId>
        <version>${graalvm.version}</version>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js</artifactId>
        <version>${graalvm.version}</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.graalvm.js</groupId>
        <artifactId>js-scriptengine</artifactId>
        <version>${graalvm.version}</version>
    </dependency>
</dependencies>

In our task listeners the following JavaScript is used:

var myVar = task.execution.getVariable("myVar")

Using JDK 11 (which internally uses Nashorn), this code works without errors.
Using JDK 17 (which uses GraalVM JS), this code breaks with:

org.camunda.bpm.engine.ProcessEngineException: ENGINE-03051 There was an exception while invoking the TaskListener. Message: 'Unable to evaluate script while executing activity 'say-hello' in the process definition with id 'my-project-process:4:42c43593-66b6-11ee-ad94-4ed774a7ec18':org.graalvm.polyglot.PolyglotException: TypeError: Cannot read property 'getVariable' of undefined'

	at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.invokeTaskListenerException(EnginePersistenceLogger.java:466)
	at org.camunda.bpm.engine.impl.persistence.entity.TaskEntity.invokeListener(TaskEntity.java:1088)
	at org.camunda.bpm.engine.impl.persistence.entity.TaskEntity.fireEvent(TaskEntity.java:1034)
	at org.camunda.bpm.engine.impl.persistence.entity.TaskEntity.transitionTo(TaskEntity.java:1178)
	at org.camunda.bpm.engine.impl.bpmn.behavior.UserTaskActivityBehavior.performExecution(UserTaskActivityBehavior.java:62)
	at org.camunda.bpm.engine.impl.bpmn.behavior.TaskActivityBehavior.execute(TaskActivityBehavior.java:69)
	at

This problem applies to Camunda 7.18, 7.19 and 7.20.

If I modify my JS code to it works on both engines:

var myVar = task.getVariable("myVar")

Is there any explanation of this behaviour?

I would like to avoid changing of hundreds of customer’s scripts if I could just register a context of task.execution somewhere…

Cheers,

Simon

1 Like

Hi @zambrovski ,

I vaguely remember that we had to change expressions like task.execution to task.getExecution(), so from properties to method calls.

Another idea you could give a shot would be to register GraalVM with compatibility options:

@Slf4j
public class NashornCompatibilityPlugin extends AbstractProcessEnginePlugin {

    @Override
    public void preInit(ProcessEngineConfigurationImpl processEngineConfiguration) {
        processEngineConfiguration.setScriptEngineResolver(new GraalVMScriptEngineResolver(new ScriptEngineManager()));
        log.info("Activated compatibility mode for Nashorn Engine.");
    }

    private static class GraalVMScriptEngineResolver extends DefaultScriptEngineResolver {

        public GraalVMScriptEngineResolver(ScriptEngineManager scriptEngineManager) {
            super(scriptEngineManager);
        }

        @Override
        protected void configureGraalJsScriptEngine(ScriptEngine scriptEngine) {
            // do nothing
        }

        @Override
        protected ScriptEngine getJavaScriptScriptEngine(String language) {
            return GraalJSScriptEngine.create(
                    // see: https://www.graalvm.org/22.0/reference-manual/js/FAQ/#warning-implementation-does-not-support-runtime-compilation
                    Engine.newBuilder().option("engine.WarnInterpreterOnly", "false").build(),
                    Context.newBuilder("js")
                           // make sure GraalVM JS can provide access to the host and can lookup classes
                           .allowHostAccess(HostAccess.ALL)
                           .allowHostClassLookup(s -> true)
                           // enable Nashorn Compatibility Mode
                           .allowExperimentalOptions(true)
                           .option("js.nashorn-compat", "true")
            );
        }
    }
}

And as last resort there would be option to implement a custom ELResolver that extends the default behaviour, but that would be quite hacky for this use case I think.

Kind regards
Adagatiya

1 Like