Thu, 07 Nov 2013 18:11:12 +0530
Merge
1.1 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Tue Nov 05 13:09:40 2013 +0400 1.2 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Thu Nov 07 18:11:12 2013 +0530 1.3 @@ -595,6 +595,21 @@ 1.4 } 1.5 1.6 /** 1.7 + * Utilitity to convert this script object to the given type. 1.8 + * 1.9 + * @param type destination type to convert to 1.10 + * @return converted object 1.11 + */ 1.12 + public <T> T to(final Class<T> type) { 1.13 + return inGlobal(new Callable<T>() { 1.14 + @Override 1.15 + public T call() { 1.16 + return type.cast(ScriptUtils.convert(sobj, type)); 1.17 + } 1.18 + }); 1.19 + } 1.20 + 1.21 + /** 1.22 * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. 1.23 * 1.24 * @param obj object to be wrapped/converted
2.1 --- a/src/jdk/nashorn/api/scripting/ScriptUtils.java Tue Nov 05 13:09:40 2013 +0400 2.2 +++ b/src/jdk/nashorn/api/scripting/ScriptUtils.java Thu Nov 07 18:11:12 2013 +0530 2.3 @@ -25,13 +25,17 @@ 2.4 2.5 package jdk.nashorn.api.scripting; 2.6 2.7 +import java.lang.invoke.MethodHandle; 2.8 +import jdk.internal.dynalink.beans.StaticClass; 2.9 +import jdk.internal.dynalink.linker.LinkerServices; 2.10 +import jdk.nashorn.internal.runtime.linker.Bootstrap; 2.11 import jdk.nashorn.internal.runtime.Context; 2.12 import jdk.nashorn.internal.runtime.ScriptFunction; 2.13 import jdk.nashorn.internal.runtime.ScriptObject; 2.14 import jdk.nashorn.internal.runtime.ScriptRuntime; 2.15 2.16 /** 2.17 - * Utilities that are to be called from script code 2.18 + * Utilities that are to be called from script code. 2.19 */ 2.20 public final class ScriptUtils { 2.21 private ScriptUtils() {} 2.22 @@ -128,4 +132,41 @@ 2.23 2.24 return ScriptObjectMirror.unwrapArray(args, Context.getGlobal()); 2.25 } 2.26 + 2.27 + /** 2.28 + * Convert the given object to the given type. 2.29 + * 2.30 + * @param obj object to be converted 2.31 + * @param type destination type to convert to 2.32 + * @return converted object 2.33 + */ 2.34 + public static Object convert(final Object obj, final Object type) { 2.35 + if (obj == null) { 2.36 + return null; 2.37 + } 2.38 + 2.39 + final Class<?> clazz; 2.40 + if (type instanceof Class) { 2.41 + clazz = (Class<?>)type; 2.42 + } else if (type instanceof StaticClass) { 2.43 + clazz = ((StaticClass)type).getRepresentedClass(); 2.44 + } else { 2.45 + throw new IllegalArgumentException("type expected"); 2.46 + } 2.47 + 2.48 + final LinkerServices linker = Bootstrap.getLinkerServices(); 2.49 + final MethodHandle converter = linker.getTypeConverter(obj.getClass(), clazz); 2.50 + if (converter == null) { 2.51 + // no supported conversion! 2.52 + throw new UnsupportedOperationException("conversion not supported"); 2.53 + } 2.54 + 2.55 + try { 2.56 + return converter.invoke(obj); 2.57 + } catch (final RuntimeException | Error e) { 2.58 + throw e; 2.59 + } catch (final Throwable t) { 2.60 + throw new RuntimeException(t); 2.61 + } 2.62 + } 2.63 }
3.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java Tue Nov 05 13:09:40 2013 +0400 3.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Thu Nov 07 18:11:12 2013 +0530 3.3 @@ -88,6 +88,9 @@ 3.4 /** JavaScript compliant conversion function from Object to number */ 3.5 public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class); 3.6 3.7 + /** JavaScript compliant conversion function from Object to String */ 3.8 + public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class); 3.9 + 3.10 /** JavaScript compliant conversion function from Object to int32 */ 3.11 public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class); 3.12
4.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Tue Nov 05 13:09:40 2013 +0400 4.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Thu Nov 07 18:11:12 2013 +0530 4.3 @@ -33,14 +33,18 @@ 4.4 import java.lang.invoke.MethodType; 4.5 import java.lang.reflect.Method; 4.6 import java.lang.reflect.Modifier; 4.7 +import java.util.Map; 4.8 +import java.util.HashMap; 4.9 import jdk.internal.dynalink.CallSiteDescriptor; 4.10 import jdk.internal.dynalink.beans.BeansLinker; 4.11 import jdk.internal.dynalink.linker.GuardedInvocation; 4.12 import jdk.internal.dynalink.linker.GuardingDynamicLinker; 4.13 +import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; 4.14 import jdk.internal.dynalink.linker.LinkRequest; 4.15 import jdk.internal.dynalink.linker.LinkerServices; 4.16 import jdk.internal.dynalink.support.Guards; 4.17 import jdk.nashorn.internal.runtime.Context; 4.18 +import jdk.nashorn.internal.runtime.JSType; 4.19 import jdk.nashorn.internal.runtime.ScriptRuntime; 4.20 4.21 /** 4.22 @@ -50,7 +54,7 @@ 4.23 * setters for Java objects that couldn't be linked by any other linker, and throw appropriate ECMAScript errors for 4.24 * attempts to invoke arbitrary Java objects as functions or constructors. 4.25 */ 4.26 -final class NashornBottomLinker implements GuardingDynamicLinker { 4.27 +final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeConverterFactory { 4.28 4.29 @Override 4.30 public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) 4.31 @@ -129,6 +133,29 @@ 4.32 throw new AssertionError("unknown call type " + desc); 4.33 } 4.34 4.35 + @Override 4.36 + public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception { 4.37 + final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType); 4.38 + return gi == null ? null : gi.asType(MH.type(targetType, sourceType)); 4.39 + } 4.40 + 4.41 + /** 4.42 + * Main part of the implementation of {@link GuardingTypeConverterFactory#convertToType(Class, Class)} that doesn't 4.43 + * care about adapting the method signature; that's done by the invoking method. Returns conversion from Object to String/number/boolean (JS primitive types). 4.44 + * @param sourceType the source type 4.45 + * @param targetType the target type 4.46 + * @return a guarded invocation that converts from the source type to the target type. 4.47 + * @throws Exception if something goes wrong 4.48 + */ 4.49 + private static GuardedInvocation convertToTypeNoCast(final Class<?> sourceType, final Class<?> targetType) throws Exception { 4.50 + final MethodHandle mh = CONVERTERS.get(targetType); 4.51 + if (mh != null) { 4.52 + return new GuardedInvocation(mh, null); 4.53 + } 4.54 + 4.55 + return null; 4.56 + } 4.57 + 4.58 private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) { 4.59 return Bootstrap.asType(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc); 4.60 } 4.61 @@ -161,6 +188,15 @@ 4.62 throw new AssertionError("unknown call type " + desc); 4.63 } 4.64 4.65 + private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>(); 4.66 + static { 4.67 + CONVERTERS.put(boolean.class, JSType.TO_BOOLEAN.methodHandle()); 4.68 + CONVERTERS.put(double.class, JSType.TO_NUMBER.methodHandle()); 4.69 + CONVERTERS.put(int.class, JSType.TO_INTEGER.methodHandle()); 4.70 + CONVERTERS.put(long.class, JSType.TO_LONG.methodHandle()); 4.71 + CONVERTERS.put(String.class, JSType.TO_STRING.methodHandle()); 4.72 + } 4.73 + 4.74 private static String getArgument(final LinkRequest linkRequest) { 4.75 final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); 4.76 if (desc.getNameTokenCount() > 2) {
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/script/basic/JDK-8027828.js Thu Nov 07 18:11:12 2013 +0530 5.3 @@ -0,0 +1,35 @@ 5.4 +/* 5.5 + * Copyright (c) 2010, 2013, 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. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/** 5.28 + * JDK-8027828: ClassCastException when converting return value of a Java method to boolean 5.29 + * 5.30 + * @test 5.31 + * @run 5.32 + */ 5.33 + 5.34 +var x = new java.util.HashMap() 5.35 +x.put('test', new java.io.File('test')) 5.36 +if (x.get("test")) { 5.37 + print('Found!') 5.38 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/script/basic/JDK-8027828.js.EXPECTED Thu Nov 07 18:11:12 2013 +0530 6.3 @@ -0,0 +1,1 @@ 6.4 +Found!
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/script/basic/convert.js Thu Nov 07 18:11:12 2013 +0530 7.3 @@ -0,0 +1,61 @@ 7.4 +/* 7.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/** 7.28 + * Tests for convert method of ScriptUtils. 7.29 + * 7.30 + * @test 7.31 + * @run 7.32 + */ 7.33 + 7.34 +var ScriptUtils = Java.type("jdk.nashorn.api.scripting.ScriptUtils"); 7.35 +obj = { valueOf: function() { print("hello"); return 43.3; } }; 7.36 + 7.37 +// object to double 7.38 +print(ScriptUtils.convert(obj, java.lang.Number.class)); 7.39 + 7.40 +// array to List 7.41 +var arr = [3, 44, 23, 33]; 7.42 +var list = ScriptUtils.convert(arr, java.util.List.class); 7.43 +print(list instanceof java.util.List) 7.44 +print(list); 7.45 + 7.46 +// object to Map 7.47 +obj = { foo: 333, bar: 'hello'}; 7.48 +var map = ScriptUtils.convert(obj, java.util.Map.class); 7.49 +print(map instanceof java.util.Map); 7.50 +for (m in map) { 7.51 + print(m + " " + map[m]); 7.52 +} 7.53 + 7.54 +// object to String 7.55 +obj = { toString: function() { print("in toString"); return "foo" } }; 7.56 +print(ScriptUtils.convert(obj, java.lang.String.class)); 7.57 + 7.58 +// array to Java array 7.59 +var jarr = ScriptUtils.convert(arr, Java.type("int[]")); 7.60 +print(jarr instanceof Java.type("int[]")); 7.61 +for (i in jarr) { 7.62 + print(jarr[i]); 7.63 +} 7.64 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/script/basic/convert.js.EXPECTED Thu Nov 07 18:11:12 2013 +0530 8.3 @@ -0,0 +1,14 @@ 8.4 +hello 8.5 +43.3 8.6 +true 8.7 +[3, 44, 23, 33] 8.8 +true 8.9 +foo 333 8.10 +bar hello 8.11 +in toString 8.12 +foo 8.13 +true 8.14 +3 8.15 +44 8.16 +23 8.17 +33
9.1 --- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Tue Nov 05 13:09:40 2013 +0400 9.2 +++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java Thu Nov 07 18:11:12 2013 +0530 9.3 @@ -26,6 +26,7 @@ 9.4 package jdk.nashorn.api.scripting; 9.5 9.6 import java.util.HashMap; 9.7 +import java.util.List; 9.8 import java.util.Map; 9.9 import javax.script.ScriptEngine; 9.10 import javax.script.ScriptEngineManager; 9.11 @@ -227,4 +228,28 @@ 9.12 final Object newObj = ((ScriptObjectMirror)e2obj.getMember("foo")).newObject(); 9.13 assertTrue(newObj instanceof ScriptObjectMirror); 9.14 } 9.15 + 9.16 + @Test 9.17 + public void conversionTest() throws ScriptException { 9.18 + final ScriptEngineManager m = new ScriptEngineManager(); 9.19 + final ScriptEngine e = m.getEngineByName("nashorn"); 9.20 + final ScriptObjectMirror arr = (ScriptObjectMirror)e.eval("[33, 45, 23]"); 9.21 + final int[] intArr = arr.to(int[].class); 9.22 + assertEquals(intArr[0], 33); 9.23 + assertEquals(intArr[1], 45); 9.24 + assertEquals(intArr[2], 23); 9.25 + 9.26 + final List<?> list = arr.to(List.class); 9.27 + assertEquals(list.get(0), 33); 9.28 + assertEquals(list.get(1), 45); 9.29 + assertEquals(list.get(2), 23); 9.30 + 9.31 + ScriptObjectMirror obj = (ScriptObjectMirror)e.eval( 9.32 + "({ valueOf: function() { return 42 } })"); 9.33 + assertEquals(Double.valueOf(42.0), obj.to(Double.class)); 9.34 + 9.35 + obj = (ScriptObjectMirror)e.eval( 9.36 + "({ toString: function() { return 'foo' } })"); 9.37 + assertEquals("foo", obj.to(String.class)); 9.38 + } 9.39 }