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.
This commit is contained in:
nboyd%atg.com 2008-01-03 18:39:04 +00:00
Родитель a1eb01d71b
Коммит 25a7cab519
4 изменённых файлов: 72 добавлений и 72 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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) {

Просмотреть файл

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

Просмотреть файл

@ -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());
}
@ -67,55 +67,21 @@ public class VMBridge_jdk15 extends org.mozilla.javascript.jdk13.VMBridge_jdk13
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) {
/**
* 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;
}
}