-RhinoのCollection対応方法

まったくMaya固有の内容ではないので、明日つかえるトリビアかな。。。まずはWrapFactoryのオーバーライド。型をみてラッパーを選択するだけの内容です。

public class MayaWrapFactory extends WrapFactory {
  public Scriptable wrapAsJavaObject(Context cx, Scriptable scope,
      Object javaObject, Class staticType) {
    if(javaObject instanceof Map) {
      return new NativeJavaMap(scope, (Map)javaObject);
    }
    return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
  }  
}

そして、Mapをラップするオブジェクト。

public class NativeJavaMap extends NativeJavaObject {
  private static final long serialVersionUID = -3987211835989098780L;
  private Map _map;
  public NativeJavaMap(Scriptable scope, Map map) {
    super(scope, map, Map.class);
    if(map == null) {
      throw new IllegalArgumentException();
    }
    _map = map;
  }
  public boolean has(String name, Scriptable start) {
    if(_map.containsKey(name)) {
      return true;
    }
    return super.has(name, start);
  }  
  public Object get(String name, Scriptable start) {
    if(_map.containsKey(name)) {
      return _map.get(name);
    }
    return super.get(name, start);
  }
  public void put(String name, Scriptable start, Object value) {
    _map.put(name, value);
  }
  public Object getIds() {
    Set set = new HashSet(_map.keySet());
    Object ids = super.getIds();
    for(int i = 0; i < ids.length; i++) {
      Object name = ids[i];
      if(set.contains(name) == false) {
        continue;
      }
      set.add(name);
    }
    return set.toArray(new Object[set.size()]);
  }
  public String getClassName() {
    return "javaMap";
  }
}

以下は、テストコード。

public class NativeJavaMapTest extends TestCase {
  public void testGet() {
    Context cx = Context.enter();
    cx.setWrapFactory(new MayaWrapFactory());
    Scriptable scope = cx.initStandardObjects();
    Map map = new HashMap();
    Object obj = Context.javaToJS(map, scope);
    ScriptableObject.putProperty(scope, "map", obj);
    map.put("testKey", "testValue");
    Object obj = _cx.evaluateString(scope, "map.testKey", null, 0, null);
    String s = (String)JavaAdapter.convertResult(obj, String.class);
    assertEquals("testValue", s);
    Context.exit();
  }
}