Tue, 26 May 2015 14:37:14 +0200
8081015: Allow conversion of native arrays to Queue and Collection
Reviewed-by: hannesw, lagergren, sundar
1.1 --- a/src/jdk/nashorn/internal/objects/NativeJava.java Thu May 21 21:51:48 2015 +0530 1.2 +++ b/src/jdk/nashorn/internal/objects/NativeJava.java Tue May 26 14:37:14 2015 +0200 1.3 @@ -33,10 +33,10 @@ 1.4 import java.util.Collection; 1.5 import java.util.Deque; 1.6 import java.util.List; 1.7 +import java.util.Queue; 1.8 import jdk.internal.dynalink.beans.StaticClass; 1.9 import jdk.internal.dynalink.support.TypeUtilities; 1.10 import jdk.nashorn.api.scripting.JSObject; 1.11 -import jdk.nashorn.api.scripting.ScriptUtils; 1.12 import jdk.nashorn.internal.objects.annotations.Attribute; 1.13 import jdk.nashorn.internal.objects.annotations.Function; 1.14 import jdk.nashorn.internal.objects.annotations.ScriptClass; 1.15 @@ -339,7 +339,8 @@ 1.16 1.17 /** 1.18 * Given a script object and a Java type, converts the script object into the desired Java type. Currently it 1.19 - * performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example: 1.20 + * performs shallow creation of Java arrays, as well as wrapping of objects in Lists, Dequeues, Queues, 1.21 + * and Collections. Example: 1.22 * <pre> 1.23 * var anArray = [1, "13", false] 1.24 * var javaIntArray = Java.to(anArray, "int[]") 1.25 @@ -353,9 +354,10 @@ 1.26 * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be 1.27 * omitted). 1.28 * @return a Java object whose value corresponds to the original script object's value. Specifically, for array 1.29 - * target types, returns a Java array of the same type with contents converted to the array's component type. Does 1.30 - * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper 1.31 - * around the object, see {@link ListAdapter} for details. Returns null if obj is null. 1.32 + * target types, returns a Java array of the same type with contents converted to the array's component type. 1.33 + * Converts recursively when the target type is multidimensional array. For {@link List}, {@link Deque}, 1.34 + * {@link Queue}, or {@link Collection}, returns a live wrapper around the object, see {@link ListAdapter} for 1.35 + * details. Returns null if obj is null. 1.36 * @throws ClassNotFoundException if the class described by objType is not found 1.37 */ 1.38 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 1.39 @@ -385,7 +387,7 @@ 1.40 return JSType.toJavaArray(obj, targetClass.getComponentType()); 1.41 } 1.42 1.43 - if(targetClass == List.class || targetClass == Deque.class) { 1.44 + if (targetClass == List.class || targetClass == Deque.class || targetClass == Queue.class || targetClass == Collection.class) { 1.45 return ListAdapter.create(obj); 1.46 } 1.47
2.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java Thu May 21 21:51:48 2015 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Tue May 26 14:37:14 2015 +0200 2.3 @@ -34,7 +34,6 @@ 2.4 import java.lang.reflect.Array; 2.5 import java.util.Arrays; 2.6 import java.util.Collections; 2.7 -import java.util.Deque; 2.8 import java.util.List; 2.9 import jdk.internal.dynalink.beans.StaticClass; 2.10 import jdk.nashorn.api.scripting.AbstractJSObject; 2.11 @@ -202,12 +201,6 @@ 2.12 /** Method handle to convert a JS Object to a Java array. */ 2.13 public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class); 2.14 2.15 - /** Method handle to convert a JS Object to a Java List. */ 2.16 - public static final Call TO_JAVA_LIST = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaList", List.class, Object.class); 2.17 - 2.18 - /** Method handle to convert a JS Object to a Java deque. */ 2.19 - public static final Call TO_JAVA_DEQUE = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaDeque", Deque.class, Object.class); 2.20 - 2.21 /** Method handle for void returns. */ 2.22 public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class); 2.23 2.24 @@ -1352,24 +1345,6 @@ 2.25 } 2.26 2.27 /** 2.28 - * Converts a JavaScript object to a Java List. See {@link ListAdapter} for details. 2.29 - * @param obj the object to convert. Can be any array-like object. 2.30 - * @return a List that is live-backed by the JavaScript object. 2.31 - */ 2.32 - public static List<?> toJavaList(final Object obj) { 2.33 - return ListAdapter.create(obj); 2.34 - } 2.35 - 2.36 - /** 2.37 - * Converts a JavaScript object to a Java Deque. See {@link ListAdapter} for details. 2.38 - * @param obj the object to convert. Can be any array-like object. 2.39 - * @return a Deque that is live-backed by the JavaScript object. 2.40 - */ 2.41 - public static Deque<?> toJavaDeque(final Object obj) { 2.42 - return ListAdapter.create(obj); 2.43 - } 2.44 - 2.45 - /** 2.46 * Check if an object is null or undefined 2.47 * 2.48 * @param obj object to check
3.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Thu May 21 21:51:48 2015 +0530 3.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Tue May 26 14:37:14 2015 +0200 3.3 @@ -29,13 +29,15 @@ 3.4 3.5 import java.lang.invoke.MethodHandle; 3.6 import java.lang.invoke.MethodHandles; 3.7 -import java.lang.invoke.MethodHandles.Lookup; 3.8 +import java.lang.invoke.MethodType; 3.9 import java.lang.reflect.Modifier; 3.10 import java.security.AccessController; 3.11 import java.security.PrivilegedAction; 3.12 +import java.util.Collection; 3.13 import java.util.Deque; 3.14 import java.util.List; 3.15 import java.util.Map; 3.16 +import java.util.Queue; 3.17 import javax.script.Bindings; 3.18 import jdk.internal.dynalink.CallSiteDescriptor; 3.19 import jdk.internal.dynalink.linker.ConversionComparator; 3.20 @@ -47,11 +49,13 @@ 3.21 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; 3.22 import jdk.internal.dynalink.support.Guards; 3.23 import jdk.internal.dynalink.support.LinkerServicesImpl; 3.24 +import jdk.internal.dynalink.support.Lookup; 3.25 import jdk.nashorn.api.scripting.JSObject; 3.26 import jdk.nashorn.api.scripting.ScriptObjectMirror; 3.27 import jdk.nashorn.api.scripting.ScriptUtils; 3.28 import jdk.nashorn.internal.objects.NativeArray; 3.29 import jdk.nashorn.internal.runtime.JSType; 3.30 +import jdk.nashorn.internal.runtime.ListAdapter; 3.31 import jdk.nashorn.internal.runtime.ScriptFunction; 3.32 import jdk.nashorn.internal.runtime.ScriptObject; 3.33 import jdk.nashorn.internal.runtime.Undefined; 3.34 @@ -167,7 +171,7 @@ 3.35 return null; 3.36 } 3.37 3.38 - private static Lookup getCurrentLookup() { 3.39 + private static java.lang.invoke.MethodHandles.Lookup getCurrentLookup() { 3.40 final LinkRequest currentRequest = AccessController.doPrivileged(new PrivilegedAction<LinkRequest>() { 3.41 @Override 3.42 public LinkRequest run() { 3.43 @@ -179,12 +183,12 @@ 3.44 3.45 /** 3.46 * Returns a guarded invocation that converts from a source type that is NativeArray to a Java array or List or 3.47 - * Deque type. 3.48 + * Queue or Deque or Collection type. 3.49 * @param sourceType the source type (presumably NativeArray a superclass of it) 3.50 - * @param targetType the target type (presumably an array type, or List or Deque) 3.51 + * @param targetType the target type (presumably an array type, or List or Queue, or Deque, or Collection) 3.52 * @return a guarded invocation that converts from the source type to the target type. null is returned if 3.53 * either the source type is neither NativeArray, nor a superclass of it, or if the target type is not an array 3.54 - * type, List, or Deque. 3.55 + * type, List, Queue, Deque, or Collection. 3.56 */ 3.57 private static GuardedInvocation getArrayConverter(final Class<?> sourceType, final Class<?> targetType) { 3.58 final boolean isSourceTypeNativeArray = sourceType == NativeArray.class; 3.59 @@ -195,12 +199,14 @@ 3.60 final MethodHandle guard = isSourceTypeGeneric ? IS_NATIVE_ARRAY : null; 3.61 if(targetType.isArray()) { 3.62 return new GuardedInvocation(ARRAY_CONVERTERS.get(targetType), guard); 3.63 - } 3.64 - if(targetType == List.class) { 3.65 - return new GuardedInvocation(JSType.TO_JAVA_LIST.methodHandle(), guard); 3.66 - } 3.67 - if(targetType == Deque.class) { 3.68 - return new GuardedInvocation(JSType.TO_JAVA_DEQUE.methodHandle(), guard); 3.69 + } else if(targetType == List.class) { 3.70 + return new GuardedInvocation(TO_LIST, guard); 3.71 + } else if(targetType == Deque.class) { 3.72 + return new GuardedInvocation(TO_DEQUE, guard); 3.73 + } else if(targetType == Queue.class) { 3.74 + return new GuardedInvocation(TO_QUEUE, guard); 3.75 + } else if(targetType == Collection.class) { 3.76 + return new GuardedInvocation(TO_COLLECTION, guard); 3.77 } 3.78 } 3.79 return null; 3.80 @@ -286,6 +292,23 @@ 3.81 private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", Boolean.TYPE, Object.class); 3.82 private static final MethodHandle CREATE_MIRROR = findOwnMH("createMirror", Object.class, Object.class); 3.83 3.84 + private static final MethodHandle TO_COLLECTION; 3.85 + private static final MethodHandle TO_DEQUE; 3.86 + private static final MethodHandle TO_LIST; 3.87 + private static final MethodHandle TO_QUEUE; 3.88 + static { 3.89 + final MethodHandle listAdapterCreate = new Lookup(MethodHandles.lookup()).findStatic( 3.90 + ListAdapter.class, "create", MethodType.methodType(ListAdapter.class, Object.class)); 3.91 + TO_COLLECTION = asReturning(listAdapterCreate, Collection.class); 3.92 + TO_DEQUE = asReturning(listAdapterCreate, Deque.class); 3.93 + TO_LIST = asReturning(listAdapterCreate, List.class); 3.94 + TO_QUEUE = asReturning(listAdapterCreate, Queue.class); 3.95 + } 3.96 + 3.97 + private static MethodHandle asReturning(final MethodHandle mh, final Class<?> nrtype) { 3.98 + return mh.asType(mh.type().changeReturnType(nrtype)); 3.99 + } 3.100 + 3.101 @SuppressWarnings("unused") 3.102 private static boolean isNashornTypeOrUndefined(final Object obj) { 3.103 return obj instanceof ScriptObject || obj instanceof Undefined;
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/src/jdk/nashorn/internal/runtime/test/JDK_8081015_Test.java Tue May 26 14:37:14 2015 +0200 4.3 @@ -0,0 +1,74 @@ 4.4 +/* 4.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. Oracle designates this 4.11 + * particular file as subject to the "Classpath" exception as provided 4.12 + * by Oracle in the LICENSE file that accompanied this code. 4.13 + * 4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.17 + * version 2 for more details (a copy is included in the LICENSE file that 4.18 + * accompanied this code). 4.19 + * 4.20 + * You should have received a copy of the GNU General Public License version 4.21 + * 2 along with this work; if not, write to the Free Software Foundation, 4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.23 + * 4.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.25 + * or visit www.oracle.com if you need additional information or have any 4.26 + * questions. 4.27 + */ 4.28 + 4.29 +package jdk.nashorn.internal.runtime.test; 4.30 + 4.31 +import static org.testng.Assert.assertEquals; 4.32 +import static org.testng.Assert.assertNull; 4.33 + 4.34 +import jdk.nashorn.test.models.JDK_8081015_TestModel; 4.35 + 4.36 +import java.util.Collection; 4.37 +import java.util.Queue; 4.38 +import javax.script.ScriptEngine; 4.39 +import javax.script.ScriptException; 4.40 +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; 4.41 +import org.testng.annotations.Test; 4.42 + 4.43 +/** 4.44 + * @bug 8081015 4.45 + * @summary Test that native arrays get converted to {@link Queue} and {@link Collection}. 4.46 + */ 4.47 +public class JDK_8081015_Test { 4.48 + @Test 4.49 + public void testConvertToCollection() throws ScriptException { 4.50 + test("receiveCollection"); 4.51 + } 4.52 + 4.53 + @Test 4.54 + public void testConvertToDeque() throws ScriptException { 4.55 + test("receiveDeque"); 4.56 + } 4.57 + 4.58 + @Test 4.59 + public void testConvertToList() throws ScriptException { 4.60 + test("receiveList"); 4.61 + } 4.62 + 4.63 + @Test 4.64 + public void testConvertToQueue() throws ScriptException { 4.65 + test("receiveQueue"); 4.66 + } 4.67 + 4.68 + private void test(final String methodName) throws ScriptException { 4.69 + final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(); 4.70 + final JDK_8081015_TestModel model = new JDK_8081015_TestModel(); 4.71 + engine.put("test", model); 4.72 + 4.73 + assertNull(model.getLastInvoked()); 4.74 + engine.eval("test." + methodName + "([1, 2, 3.3, 'foo'])"); 4.75 + assertEquals(model.getLastInvoked(), methodName ); 4.76 + } 4.77 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/src/jdk/nashorn/test/models/JDK_8081015_TestModel.java Tue May 26 14:37:14 2015 +0200 5.3 @@ -0,0 +1,73 @@ 5.4 +/* 5.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. Oracle designates this 5.11 + * particular file as subject to the "Classpath" exception as provided 5.12 + * by Oracle in the LICENSE file that accompanied this code. 5.13 + * 5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.17 + * version 2 for more details (a copy is included in the LICENSE file that 5.18 + * accompanied this code). 5.19 + * 5.20 + * You should have received a copy of the GNU General Public License version 5.21 + * 2 along with this work; if not, write to the Free Software Foundation, 5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.23 + * 5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.25 + * or visit www.oracle.com if you need additional information or have any 5.26 + * questions. 5.27 + */ 5.28 + 5.29 +package jdk.nashorn.test.models; 5.30 + 5.31 +import static org.testng.Assert.assertEquals; 5.32 +import static org.testng.Assert.assertFalse; 5.33 + 5.34 +import java.util.Collection; 5.35 +import java.util.Deque; 5.36 +import java.util.Iterator; 5.37 +import java.util.List; 5.38 +import java.util.Queue; 5.39 + 5.40 +@SuppressWarnings("javadoc") 5.41 +public class JDK_8081015_TestModel { 5.42 + private String lastInvoked; 5.43 + 5.44 + public void receiveCollection(final Collection<Object> c) { 5.45 + lastInvoked = "receiveCollection"; 5.46 + walkCollection(c); 5.47 + } 5.48 + 5.49 + public void receiveDeque(final Deque<Object> d) { 5.50 + lastInvoked = "receiveDeque"; 5.51 + walkCollection(d); 5.52 + } 5.53 + 5.54 + public void receiveList(final List<Object> l) { 5.55 + lastInvoked = "receiveList"; 5.56 + walkCollection(l); 5.57 + } 5.58 + 5.59 + public void receiveQueue(final Queue<Object> q) { 5.60 + lastInvoked = "receiveQueue"; 5.61 + walkCollection(q); 5.62 + } 5.63 + 5.64 + public String getLastInvoked() { 5.65 + return lastInvoked; 5.66 + } 5.67 + 5.68 + private static void walkCollection(final Collection<Object> c) { 5.69 + final Iterator<Object> it = c.iterator(); 5.70 + assertEquals(it.next(), Integer.valueOf(1)); 5.71 + assertEquals(it.next(), Integer.valueOf(2)); 5.72 + assertEquals(it.next(), Double.valueOf(3.3)); 5.73 + assertEquals(it.next(), "foo"); 5.74 + assertFalse(it.hasNext()); 5.75 + } 5.76 +}