I am trying to write a library that will let me execute JSON Logic rules via the Nashorn Javascript engine.
My problem right now is specifically around the JSObject wrapper I've created to handle moving data from Java/Kotlin into the scripting engine.
If an array is passed in such as [true]
it is wrapped and the json-logic script will receive it, see that it is an array, and attempt to run the following bit of code:
if(Array.isArray(logic)) {
return logic.map(function(l) {
return jsonLogic.apply(l, data);
});
}
When the .map
function is called, Nashorn will call getMember("map")
on my object expecting to get a function back that it can execute.
This is where I am stuck. I have not been able to find any sort of proper syntax to give Nashorn a method or method reference that can be invoked by it as the receiver of its map function.
The code is available here: https://github.com/deinspanjer/json-logic-java
There are some basic unit tests including the one that exhibits the problem, JavaJsonLogicTest.simpleApplyJEJO()
.
The line of code that is broken is com/jsonlogic/JSObjectWrappers.kt:97
.
I would very much appreciate your help.
UPDATE: Based on the accepted answer, here is the working Kotlin version of the code:
package com.jsonlogic
import jdk.nashorn.api.scripting.AbstractJSObject
import jdk.nashorn.api.scripting.JSObject
import java.util.function.Function
import javax.script.ScriptEngineManager
fun main(args: Array<String>) {
val m = ScriptEngineManager()
val e = m.getEngineByName("nashorn")
// The following JSObject wraps this list
val l = mutableListOf<Any>()
l.add("hello")
l.add("world")
l.add(true)
l.add(1)
val jsObj = object : AbstractJSObject() {
override fun getMember(name: String?): Any? {
if (name == "map") {
// return a functional interface object - nashorn will treat it like
// script function!
return Function { callback: JSObject ->
val res = l.map {
// call callback on each object and add the result to new list
callback.call(null, it)
}
// return fresh list as result of map (or this could be another wrapper)
res
}
} else {
// unknown property
return null
}
}
}
e.put("obj", jsObj)
// map each String to it's uppercase and print result of map
e.eval("print(obj.map(function(x) '\"'+x.toString()+'\"'))");
}