# HG changeset patch
# User attila
# Date 1369303295 -7200
# Node ID 1c1453863ea889f8bec47e3a9d9f90802382d03e
# Parent 8f7553df4503c5cd800c6c5196c2295bd50f2255
8015267: Allow conversion of JS arrays to Java List/Deque
Reviewed-by: lagergren, sundar
diff -r 8f7553df4503 -r 1c1453863ea8 make/build.xml
--- a/make/build.xml Wed May 22 16:43:48 2013 +0200
+++ b/make/build.xml Thu May 23 12:01:35 2013 +0200
@@ -42,8 +42,6 @@
-
-
@@ -80,19 +78,7 @@
-
-
-
-
-
-
+
* var anArray = [1, "13", false]
* var javaIntArray = Java.to(anArray, "int[]")
@@ -250,42 +253,46 @@
* print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
*
* @param self not used
- * @param objArray the script object. Can be null.
+ * @param obj the script object. Can be null.
* @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java
* object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be
* omitted).
* @return a Java object whose value corresponds to the original script object's value. Specifically, for array
* target types, returns a Java array of the same type with contents converted to the array's component type. Does
- * not recursively convert for multidimensional arrays.
- * type. Returns null if scriptObject is null.
+ * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper
+ * around the object, see {@link ListAdapter} for details. Returns null if obj is null.
* @throws ClassNotFoundException if the class described by objType is not found
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object to(final Object self, final Object objArray, final Object objType) throws ClassNotFoundException {
- if (objArray == null) {
+ public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException {
+ if (obj == null) {
return null;
}
- final Class> componentType;
+ Global.checkObject(obj);
+
+ final Class> targetClass;
if(objType == UNDEFINED) {
- componentType = Object.class;
+ targetClass = Object[].class;
} else {
- final StaticClass arrayType;
+ final StaticClass targetType;
if(objType instanceof StaticClass) {
- arrayType = (StaticClass)objType;
+ targetType = (StaticClass)objType;
} else {
- arrayType = type(objType);
+ targetType = type(objType);
}
- final Class> arrayClass = arrayType.getRepresentedClass();
- if(!arrayClass.isArray()) {
- throw typeError("to.expects.array.type", arrayClass.getName());
- }
- componentType = arrayClass.getComponentType();
+ targetClass = targetType.getRepresentedClass();
}
- Global.checkObject(objArray);
+ if(targetClass.isArray()) {
+ return ((ScriptObject)obj).getArray().asArrayOfType(targetClass.getComponentType());
+ }
- return ((ScriptObject)objArray).getArray().asArrayOfType(componentType);
+ if(targetClass == List.class || targetClass == Deque.class) {
+ return new ListAdapter((ScriptObject)obj);
+ }
+
+ throw typeError("unsupported.java.to.type", targetClass.getName());
}
/**
diff -r 8f7553df4503 -r 1c1453863ea8 src/jdk/nashorn/internal/runtime/ListAdapter.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/internal/runtime/ListAdapter.java Thu May 23 12:01:35 2013 +0200
@@ -0,0 +1,337 @@
+package jdk.nashorn.internal.runtime;
+
+import java.util.AbstractList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+import jdk.nashorn.internal.runtime.linker.InvokeByName;
+
+/**
+ * An adapter that can wrap any ECMAScript Array-like object (that adheres to the array rules for the property
+ * {@code length} and having conforming {@code push}, {@code pop}, {@code shift}, {@code unshift}, and {@code splice}
+ * methods) and expose it as both a Java list and double-ended queue. While script arrays aren't necessarily efficient
+ * as dequeues, it's still slightly more efficient to be able to translate dequeue operations into pushes, pops, shifts,
+ * and unshifts, than to blindly translate all list's add/remove operations into splices. Also, it is conceivable that a
+ * custom script object that implements an Array-like API can have a background data representation that is optimized
+ * for dequeue-like access. Note that with ECMAScript arrays, {@code push} and {@pop} operate at the end of the array,
+ * while in Java {@code Deque} they operate on the front of the queue and as such the Java dequeue {@link #push(Object)}
+ * and {@link #pop()} operations will translate to {@code unshift} and {@code shift} script operations respectively,
+ * while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and {@code pop}.
+ */
+public class ListAdapter extends AbstractList