Accessing java Maps & Lists as JavaScript Objects in Rhino
Asked Answered
D

6

8

Is there a way to access Java Maps and Lists as JavaScript Objects in Rhino?

I have a Map which contains only other maps and lists of primitives and Strings, I'd like to pass this to a Rhino script and do stuff to it, and return the modified object back out to Java - but since they are java.util.Map and java.util.List Objects, I can't use standard JavaScript associative array syntax. ie: fooMap.get("keyName") will work, but fooMap.keyName and fooMap["keyName"] will not.

I don't know if there is a Rhino-specific way to do this, or if there is some conversion/cast utility that will help. Commons BeanUtils is not sufficient, because to convert a Map to a bean (which can be accessed via associative array syntax), you must first create a class which has all of the named mutators/accessors. I won't know the structure of the object at runtime.

Digitalism answered 18/5, 2011 at 14:36 Comment(2)
For that matter, I would like to be able to use for (var in list) {...} syntax rather than having to use an explicit iterator.Melodramatic
FYI, similar issue regarding instantiating native objects.Newborn
J
4

Take a look at RingoJS. It has convenient wrappers for list and map for Rhino such as this one

Josiejosler answered 18/5, 2011 at 15:41 Comment(0)
F
2

iterators seem to be the key!

if you want to iterate over all entries of a map, you could do the following

JAVA

//pass  the map and map.keySet().iterator() to the javascript
Object wrappedParameterMap = Context.javaToJS(parameterMap, scope);
ScriptableObject.putProperty(scope, "parameterMap", wrappedParameterMap);
Object wrappedParameterNames = Context.javaToJS(parameterMap.keySet().iterator(), scope);
ScriptableObject.putProperty(scope, "parameterNames", wrappedParameterNames);

JAVASCRIPT

while(parameterNames.hasNext()) {
  key = parameterNames.next();
  value = parameterMap.get(key);
}
Frightfully answered 28/9, 2011 at 21:17 Comment(0)
M
1

https://developer.mozilla.org/en/New_in_Rhino_1.7R3#JS.c2.a0Objects_implement_Java_collections claims that JS objects resp. arrays can now be cast to Map resp. List, but this does not seem like it would work for your use case.

Melodramatic answered 9/8, 2011 at 14:21 Comment(0)
N
0

I had a similar problem that may be useful. I tried created native rhino objects and copied data into them.

Newborn answered 22/12, 2011 at 2:5 Comment(0)
B
0

Since Rhino 1.7.12 you can create ES6 lambdas and therefore create your own utility function like this:

function iterateMap(map, callback) {
    var iter = map.keySet().iterator();
    while(iter.hasNext()) {
        var key = iter.next();
        var value = map.get(key);
        callback(key, value);
    }
}

And then iterate like this

iterateMap(map, (key, value)=>{
    //...
});
Beating answered 22/2, 2021 at 17:29 Comment(0)
T
0

The way to achieve this since Rhino 1.7.14 is to enable Context.FEATURE_ENABLE_JAVA_MAP_ACCESS.

This requires implementing a custom ContextFactory:

public class MyContextFactory extends ContextFactory {
    @Override
    protected boolean hasFeature(Context cx, int featureIndex) {
        switch (featureIndex) {
            case Context.FEATURE_ENABLE_JAVA_MAP_ACCESS:
                return true;
        }
        return super.hasFeature(cx, featureIndex);
    }
}

Then, this factory can be used to instantiate contexts that has this feature enabled:

Map<String, String> myMap = Map.of("message", "Hello from JavaScript");

ContextFactory ctxFactory = new MyContextFactory();
try (Context ctx = ctxFactory.enterContext()) {
    Scriptable scope = ctx.initSafeStandardObjects();
    ScriptableObject.putProperty(scope, "myMap", Context.javaToJS(myMap, scope));
    
    // Now map properties are accessible via `[key]` or `.key`:
    Object result = ctx.evaluateString(scope, "myMap.message", "<sample>", 1, null);
    String message = Context.jsToJava(result, String.class);
    System.out.println(message); // prints "Hello from JavaScript"
}
Towhee answered 20/2, 2023 at 9:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.