From 25a7cab51922beff1997b7b51834e234f4f50903 Mon Sep 17 00:00:00 2001 From: "nboyd%atg.com" Date: Thu, 3 Jan 2008 18:39:04 +0000 Subject: [PATCH] I've made changes to Rhino such that its default behavior is now only to treat Iterables or Iterators specially when they are arguments to the new Iterator constructor: js> m = new java.util.HashMap() {} js> m.put("a",1) null js> m.put("b",2) null js> m {a=1.0, b=2.0} js> for (i in m.values()) print(i) notifyAll removeAll containsAll contains empty equals notify class isEmpty add size iterator clear wait retainAll toString hashCode toArray addAll getClass remove js> for (i in Iterator(m.values())) print(i) 1.0 2.0 js> for (i in Iterator(m.values().iterator())) print(i) 1.0 2.0 js> Since Iterator is a new addition for 1.7, there are no issues for backwards compatibility. This still leaves open the possibility of top-level functions to wrap Maps and Lists as JavaScript Objects and Arrays. --- .../org/mozilla/javascript/JavaMembers.java | 15 ---- .../mozilla/javascript/NativeIterator.java | 46 ++++++++++++- .../src/org/mozilla/javascript/VMBridge.java | 15 +++- .../javascript/jdk15/VMBridge_jdk15.java | 68 +++++-------------- 4 files changed, 72 insertions(+), 72 deletions(-) diff --git a/js/rhino/src/org/mozilla/javascript/JavaMembers.java b/js/rhino/src/org/mozilla/javascript/JavaMembers.java index 975e64427d9..12e197b2f82 100644 --- a/js/rhino/src/org/mozilla/javascript/JavaMembers.java +++ b/js/rhino/src/org/mozilla/javascript/JavaMembers.java @@ -640,20 +640,6 @@ class JavaMembers } } - // For objects that implement java.lang.Iterable, provide a - // __iterator__ property - if (iterableClass != null && iterableClass.isAssignableFrom(cl) && - members.get(NativeIterator.ITERATOR_PROPERTY_NAME) == null && - staticMembers.get(NativeIterator.ITERATOR_PROPERTY_NAME) == null) - { - Method m = VMBridge.instance.getIteratorMethod(); - if (m != null) { - members.put(NativeIterator.ITERATOR_PROPERTY_NAME, - new FunctionObject(NativeIterator.ITERATOR_PROPERTY_NAME, - m, scope)); - } - } - // Reflect constructors Constructor[] constructors = getAccessibleConstructors(); ctors = new MemberBox[constructors.length]; @@ -874,7 +860,6 @@ class JavaMembers private Hashtable staticFieldAndMethods; MemberBox[] ctors; private boolean includePrivate; - private static Class iterableClass = Kit.classOrNull("java.lang.Iterable"); } class BeanProperty diff --git a/js/rhino/src/org/mozilla/javascript/NativeIterator.java b/js/rhino/src/org/mozilla/javascript/NativeIterator.java index 084fa013ffb..27e515b6068 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeIterator.java +++ b/js/rhino/src/org/mozilla/javascript/NativeIterator.java @@ -30,6 +30,8 @@ package org.mozilla.javascript; +import java.util.Iterator; + /** * This class implements iterator objects. See * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Iterators @@ -161,10 +163,24 @@ public final class NativeIterator extends IdScriptableObject { boolean keyOnly = args.length > 1 && ScriptRuntime.toBoolean(args[1]); if (thisObj != null) { // Called as a function. Convert to iterator if possible. - Scriptable iterator = ScriptRuntime.toIterator(cx, scope, obj, - keyOnly); + + // For objects that implement java.lang.Iterable or + // java.util.Iterator, have JavaScript Iterator call the underlying + // iteration methods + Iterator iterator = + VMBridge.instance.getJavaIterator(cx, scope, obj); if (iterator != null) { - return iterator; + scope = ScriptableObject.getTopLevelScope(scope); + return cx.getWrapFactory().wrap(cx, scope, + new WrappedJavaIterator(iterator, scope), + WrappedJavaIterator.class); + } + + // Otherwise, just call the runtime routine + Scriptable jsIterator = ScriptRuntime.toIterator(cx, scope, obj, + keyOnly); + if (jsIterator != null) { + return jsIterator; } } @@ -194,6 +210,30 @@ public final class NativeIterator extends IdScriptableObject { return cx.newArray(scope, elements); } + static public class WrappedJavaIterator + { + WrappedJavaIterator(Iterator iterator, Scriptable scope) { + this.iterator = iterator; + this.scope = scope; + } + + public Object next() { + if (!iterator.hasNext()) { + // Out of values. Throw StopIteration. + throw new JavaScriptException( + NativeIterator.getStopIterationObject(scope), null, 0); + } + return iterator.next(); + } + + public Object __iterator__(boolean b) { + return this; + } + + private Iterator iterator; + private Scriptable scope; + } + // #string_id_map# protected int findPrototypeId(String s) { diff --git a/js/rhino/src/org/mozilla/javascript/VMBridge.java b/js/rhino/src/org/mozilla/javascript/VMBridge.java index 3c2dfd69fe0..5fba4a597e7 100644 --- a/js/rhino/src/org/mozilla/javascript/VMBridge.java +++ b/js/rhino/src/org/mozilla/javascript/VMBridge.java @@ -41,6 +41,7 @@ package org.mozilla.javascript; import java.lang.reflect.Method; import java.lang.reflect.Member; +import java.util.Iterator; public abstract class VMBridge { @@ -165,10 +166,18 @@ public abstract class VMBridge protected abstract boolean isVarArgs(Member member); /** - * return method corresponding to __iterator__ for treating a - * java.lang.Iterable as a JavaScript Iterator + * If "obj" is a java.util.Iterator or a java.lang.Iterable, return a + * wrapping as a JavaScript Iterator. Otherwise, return null. + * This method is in VMBridge since Iterable is a JDK 1.5 addition. */ - public Method getIteratorMethod() { + public Iterator getJavaIterator(Context cx, Scriptable scope, Object obj) { + if (obj instanceof Wrapper) { + Object unwrapped = ((Wrapper) obj).unwrap(); + Iterator iterator = null; + if (unwrapped instanceof Iterator) + iterator = (Iterator) unwrapped; + return iterator; + } return null; } } diff --git a/js/rhino/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java b/js/rhino/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java index 6c10b035394..0ffaf9d27e6 100644 --- a/js/rhino/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java +++ b/js/rhino/src/org/mozilla/javascript/jdk15/VMBridge_jdk15.java @@ -52,7 +52,7 @@ public class VMBridge_jdk15 extends org.mozilla.javascript.jdk13.VMBridge_jdk13 // so that we can load a bridge to an older JDK instead. Method.class.getMethod("isVarArgs", (Class[]) null); } catch (NoSuchMethodException e) { - // Throw a fittitng exception that is handled by + // Throw a fitting exception that is handled by // org.mozilla.javascript.Kit.newInstanceOrNull: throw new InstantiationException(e.getMessage()); } @@ -66,56 +66,22 @@ public class VMBridge_jdk15 extends org.mozilla.javascript.jdk13.VMBridge_jdk13 else return false; } - - public Method getIteratorMethod() { - try { - Class[] sig = { Context.class, Scriptable.class, - ScriptRuntime.emptyArgs.getClass(), - Function.class }; - return VMBridge_jdk15.class.getMethod("__iterator__", sig); - } catch (NoSuchMethodException e) { - return null; + + /** + * If "obj" is a java.util.Iterator or a java.lang.Iterable, return a + * wrapping as a JavaScript Iterator. Otherwise, return null. + * This method is in VMBridge since Iterable is a JDK 1.5 addition. + */ + public Iterator getJavaIterator(Context cx, Scriptable scope, Object obj) { + if (obj instanceof Wrapper) { + Object unwrapped = ((Wrapper) obj).unwrap(); + Iterator iterator = null; + if (unwrapped instanceof Iterator) + iterator = (Iterator) unwrapped; + if (unwrapped instanceof Iterable) + iterator = ((Iterable)unwrapped).iterator(); + return iterator; } + return null; } - - public static Object __iterator__(Context cx, Scriptable thisObj, - Object[] args, Function funObj) - { - if (thisObj instanceof Wrapper) { - Object obj = ((Wrapper) thisObj).unwrap(); - if (obj instanceof Iterable) { - Scriptable scope = ScriptableObject.getTopLevelScope(funObj); - return cx.getWrapFactory().wrap(cx, scope, - new WrappedJavaIterator((Iterable) obj, scope), - WrappedJavaIterator.class); - } - } - throw ScriptRuntime.typeError1("msg.incompat.call", - NativeIterator.ITERATOR_PROPERTY_NAME); - } - - static public class WrappedJavaIterator - { - WrappedJavaIterator(Iterable iterable, Scriptable scope) { - this.iterator = iterable.iterator(); - this.scope = scope; - } - - public Object next() { - if (!iterator.hasNext()) { - // Out of values. Throw StopIteration. - throw new JavaScriptException( - NativeIterator.getStopIterationObject(scope), null, 0); - } - return iterator.next(); - } - - public Object __iterator__() { - return this; - } - - private Iterator iterator; - private Scriptable scope; - } - }