Kotlin script engine fails on simple example


#1

This is based on some code I found online:

public class ScriptExample {
	public static void main(String[] args) {
		// Create Java array with list of cities
		String cities[] = { "London", "NewYork", "Sydney", "Bangalore",
				"Chennai", "Mumbai" };
				
		String script = "println(\"Hello, world\")";
	

		// Create ScriptEngine
		ScriptEngineManager engineManager = new ScriptEngineManager();
		ScriptEngine engine = engineManager.getEngineByName("kotlin");


		for (ScriptEngineFactory factory : engineManager.getEngineFactories()) {
			System.out.println(factory.getEngineName());
			System.out.println("\t" + factory.getLanguageName());
		}

		if (engine == null) {
			System.out.println("Engine missing");
			System.exit(1);
		}


		// Add Java object to script engine
		engine.put("citiesArray", cities);
		try {
			// Evaluate  script using script engine
			engine.eval(script);
			engine.eval("for (c in citiesArray) { println(c) }");
		} catch (ScriptException exception) {
			exception.printStackTrace();
		}
	}
}

Once it gets to the eval for the for loop, it fails with this exception:

javax.script.ScriptException: error: unresolved reference: citiesArray
for (c in citiesArray) { println(c) }
          ^

	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.compileAndEval(KotlinJsr223JvmScriptEngineBase.kt:65)
	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.eval(KotlinJsr223JvmScriptEngineBase.kt:31)
	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at ScriptExample.main(ScriptExample.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:282)
	at java.lang.Thread.run(Thread.java:748)

This works with other script engines. Is this a bug in the Kotlin implementation of the ScriptEngine API?


#2

Aside from the bad syntax, apparently you have to reference bindings through the bindings variable like this:

public class ScriptExample {
	public static void main(String[] args) {
		// Create Java array with list of cities
		java.util.List<String> cities = java.util.Arrays.asList("London", "NewYork", "Sydney", "Bangalore",
				"Chennai", "Mumbai" );
				
		String script = "println(\"Hello, world\")";
	

		// Create ScriptEngine
		ScriptEngineManager engineManager = new ScriptEngineManager();
		ScriptEngine engine = engineManager.getEngineByExtension("kts");


		for (ScriptEngineFactory factory : engineManager.getEngineFactories()) {
			System.out.println(factory.getEngineName());
			System.out.println("\t" + factory.getLanguageName());
		}

		if (engine == null) {
			System.out.println("Engine missing");
			System.exit(1);
		}


		// Add Java object to script engine
		engine.put("citiesArray", cities);
		try {
			// Evaluate  script using script engine
			engine.eval(script);
			engine.eval("for (c in (bindings[\"citiesArray\"] as List<String>)) { println(c) }");
		} catch (ScriptException exception) {
			exception.printStackTrace();
		}
	}
}

#3

This also should work. There is no need to change types.

engine.eval("for (c in (bindings[\"citiesArray\"] as Array<String>)) { println(c) }");