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.

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. Commented Aug 9, 2011 at 14:14
  • FYI, similar issue regarding instantiating native objects. Commented Dec 21, 2011 at 23:45

6 Answers 6

4

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

Sign up to request clarification or add additional context in comments.

Comments

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

Comments

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.

Comments

0

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

Comments

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)=>{
    //...
});

Comments

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"
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.