NativeJava.java revision 1297:92f7bf49eb65
1169689Skan/* 2169689Skan * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3169689Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4169689Skan * 5169689Skan * This code is free software; you can redistribute it and/or modify it 6169689Skan * under the terms of the GNU General Public License version 2 only, as 7169689Skan * published by the Free Software Foundation. Oracle designates this 8169689Skan * particular file as subject to the "Classpath" exception as provided 9169689Skan * by Oracle in the LICENSE file that accompanied this code. 10169689Skan * 11169689Skan * This code is distributed in the hope that it will be useful, but WITHOUT 12169689Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13169689Skan * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14169689Skan * version 2 for more details (a copy is included in the LICENSE file that 15169689Skan * accompanied this code). 16169689Skan * 17169689Skan * You should have received a copy of the GNU General Public License version 18169689Skan * 2 along with this work; if not, write to the Free Software Foundation, 19169689Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20169689Skan * 21169689Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22169689Skan * or visit www.oracle.com if you need additional information or have any 23169689Skan * questions. 24169689Skan */ 25169689Skan 26169689Skanpackage jdk.nashorn.internal.objects; 27169689Skan 28169689Skanimport static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29169689Skanimport static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 30169689Skan 31169689Skanimport java.lang.invoke.MethodHandles; 32169689Skanimport java.lang.reflect.Array; 33169689Skanimport java.util.Collection; 34169689Skanimport java.util.Deque; 35169689Skanimport java.util.List; 36169689Skanimport java.util.Map; 37169689Skanimport java.util.Queue; 38169689Skanimport jdk.internal.dynalink.beans.StaticClass; 39169689Skanimport jdk.internal.dynalink.support.TypeUtilities; 40169689Skanimport jdk.nashorn.api.scripting.JSObject; 41169689Skanimport jdk.nashorn.api.scripting.ScriptObjectMirror; 42169689Skanimport jdk.nashorn.internal.objects.annotations.Attribute; 43169689Skanimport jdk.nashorn.internal.objects.annotations.Function; 44169689Skanimport jdk.nashorn.internal.objects.annotations.ScriptClass; 45169689Skanimport jdk.nashorn.internal.objects.annotations.Where; 46169689Skanimport jdk.nashorn.internal.runtime.Context; 47169689Skanimport jdk.nashorn.internal.runtime.JSType; 48169689Skanimport jdk.nashorn.internal.runtime.ListAdapter; 49169689Skanimport jdk.nashorn.internal.runtime.PropertyMap; 50169689Skanimport jdk.nashorn.internal.runtime.ScriptFunction; 51169689Skanimport jdk.nashorn.internal.runtime.ScriptObject; 52169689Skanimport jdk.nashorn.internal.runtime.ScriptRuntime; 53169689Skanimport jdk.nashorn.internal.runtime.linker.Bootstrap; 54169689Skanimport jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; 55169689Skan 56169689Skan/** 57169689Skan * This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This 58169689Skan * object acts as the API entry point to Java platform specific functionality, dealing with creating new instances of 59169689Skan * Java classes, subclassing Java classes, implementing Java interfaces, converting between Java arrays and ECMAScript 60169689Skan * arrays, and so forth. 61169689Skan */ 62169689Skan@ScriptClass("Java") 63169689Skanpublic final class NativeJava { 64169689Skan 65169689Skan // initialized by nasgen 66169689Skan @SuppressWarnings("unused") 67169689Skan private static PropertyMap $nasgenmap$; 68169689Skan 69169689Skan private NativeJava() { 70169689Skan // don't create me 71169689Skan throw new UnsupportedOperationException(); 72169689Skan } 73169689Skan 74169689Skan /** 75169689Skan * Returns true if the specified object is a Java type object, that is an instance of {@link StaticClass}. 76169689Skan * @param self not used 77169689Skan * @param type the object that is checked if it is a type object or not 78169689Skan * @return tells whether given object is a Java type object or not. 79169689Skan * @see #type(Object, Object) 80169689Skan */ 81169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 82169689Skan public static boolean isType(final Object self, final Object type) { 83169689Skan return type instanceof StaticClass; 84169689Skan } 85169689Skan 86169689Skan /** 87169689Skan * Returns synchronized wrapper version of the given ECMAScript function. 88169689Skan * @param self not used 89169689Skan * @param func the ECMAScript function whose synchronized version is returned. 90169689Skan * @param obj the object (i.e, lock) on which the function synchronizes. 91169689Skan * @return synchronized wrapper version of the given ECMAScript function. 92169689Skan */ 93169689Skan @Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 94169689Skan public static Object synchronizedFunc(final Object self, final Object func, final Object obj) { 95169689Skan if (func instanceof ScriptFunction) { 96169689Skan return ((ScriptFunction)func).makeSynchronizedFunction(obj); 97169689Skan } 98169689Skan 99169689Skan throw typeError("not.a.function", ScriptRuntime.safeToString(func)); 100169689Skan } 101169689Skan 102169689Skan /** 103169689Skan * Returns true if the specified object is a Java method. 104169689Skan * @param self not used 105169689Skan * @param obj the object that is checked if it is a Java method object or not 106169689Skan * @return tells whether given object is a Java method object or not. 107169689Skan */ 108169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 109169689Skan public static boolean isJavaMethod(final Object self, final Object obj) { 110169689Skan return Bootstrap.isDynamicMethod(obj); 111169689Skan } 112169689Skan 113169689Skan /** 114169689Skan * Returns true if the specified object is a java function (but not script function) 115169689Skan * @param self not used 116169689Skan * @param obj the object that is checked if it is a Java function or not 117169689Skan * @return tells whether given object is a Java function or not 118169689Skan */ 119169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 120169689Skan public static boolean isJavaFunction(final Object self, final Object obj) { 121169689Skan return Bootstrap.isCallable(obj) && !(obj instanceof ScriptFunction); 122169689Skan } 123169689Skan 124169689Skan /** 125169689Skan * Returns true if the specified object is a Java object but not a script object 126169689Skan * @param self not used 127169689Skan * @param obj the object that is checked 128169689Skan * @return tells whether given object is a Java object but not a script object 129169689Skan */ 130169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 131169689Skan public static boolean isJavaObject(final Object self, final Object obj) { 132169689Skan return obj != null && !(obj instanceof ScriptObject); 133169689Skan } 134169689Skan 135169689Skan /** 136169689Skan * Returns true if the specified object is a ECMAScript object, that is an instance of {@link ScriptObject}. 137169689Skan * @param self not used 138169689Skan * @param obj the object that is checked if it is a ECMAScript object or not 139169689Skan * @return tells whether given object is a ECMAScript object or not. 140169689Skan */ 141169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 142169689Skan public static boolean isScriptObject(final Object self, final Object obj) { 143169689Skan return obj instanceof ScriptObject; 144169689Skan } 145169689Skan 146169689Skan /** 147169689Skan * Returns true if the specified object is a ECMAScript function, that is an instance of {@link ScriptFunction}. 148169689Skan * @param self not used 149169689Skan * @param obj the object that is checked if it is a ECMAScript function or not 150169689Skan * @return tells whether given object is a ECMAScript function or not. 151169689Skan */ 152169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 153169689Skan public static boolean isScriptFunction(final Object self, final Object obj) { 154169689Skan return obj instanceof ScriptFunction; 155169689Skan } 156169689Skan 157169689Skan /** 158169689Skan * <p> 159169689Skan * Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects 160169689Skan * used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are 161169689Skan * the objects that you can use with the {@code new} operator to create new instances of the class as well as to 162169689Skan * access static members of the class. In Nashorn, {@code Class} objects are just regular Java objects that aren't 163169689Skan * treated specially. Instead of them, {@link StaticClass} instances - which we sometimes refer to as "Java type 164169689Skan * objects" are used as constructors with the {@code new} operator, and they expose static fields, properties, and 165169689Skan * methods. While this might seem confusing at first, it actually closely matches the Java language: you use a 166169689Skan * different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is 167169689Skan * distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the 168169689Skan * properties of the type objects. 169169689Skan * </p> 170169689Skan * <p><b>Constructing Java objects</b></p> 171169689Skan * Examples: 172169689Skan * <pre> 173169689Skan * var arrayListType = Java.type("java.util.ArrayList") 174169689Skan * var intType = Java.type("int") 175169689Skan * var stringArrayType = Java.type("java.lang.String[]") 176169689Skan * var int2DArrayType = Java.type("int[][]") 177169689Skan * </pre> 178169689Skan * Note that the name of the type is always a string for a fully qualified name. You can use any of these types to 179169689Skan * create new instances, e.g.: 180169689Skan * <pre> 181169689Skan * var anArrayList = new Java.type("java.util.ArrayList") 182169689Skan * </pre> 183169689Skan * or 184169689Skan * <pre> 185169689Skan * var ArrayList = Java.type("java.util.ArrayList") 186169689Skan * var anArrayList = new ArrayList 187169689Skan * var anArrayListWithSize = new ArrayList(16) 188169689Skan * </pre> 189169689Skan * In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $} 190169689Skan * sign in the class name, or you can use the dot: 191169689Skan * <pre> 192169689Skan * var ftype = Java.type("java.awt.geom.Arc2D$Float") 193169689Skan * </pre> 194169689Skan * and 195169689Skan * <pre> 196169689Skan * var ftype = Java.type("java.awt.geom.Arc2D.Float") 197169689Skan * </pre> 198169689Skan * both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name 199169689Skan * as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the 200169689Skan * dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to 201169689Skan * dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads 202169689Skan * the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested 203169689Skan * inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An 204169689Skan * alternative way to access the inner class is as a property of the outer class: 205169689Skan * <pre> 206169689Skan * var arctype = Java.type("java.awt.geom.Arc2D") 207169689Skan * var ftype = arctype.Float 208169689Skan * </pre> 209169689Skan * <p> 210169689Skan * You can access both static and non-static inner classes. If you want to create an instance of a non-static 211169689Skan * inner class, remember to pass an instance of its outer class as the first argument to the constructor. 212169689Skan * </p> 213169689Skan * <p> 214169689Skan * If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is 215169689Skan * applicable to any of its public or protected constructors, but inserting a JavaScript object with functions 216169689Skan * properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the 217169689Skan * JavaScript function will provide implementation for all overloads. E.g.: 218169689Skan * </p> 219169689Skan * <pre> 220169689Skan * var TimerTask = Java.type("java.util.TimerTask") 221169689Skan * var task = new TimerTask({ run: function() { print("Hello World!") } }) 222169689Skan * </pre> 223169689Skan * <p> 224169689Skan * Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to 225169689Skan * invoking the constructor and passing the argument to it, so you can write the above example also as: 226169689Skan * </p> 227169689Skan * <pre> 228169689Skan * var task = new TimerTask { 229169689Skan * run: function() { 230169689Skan * print("Hello World!") 231169689Skan * } 232169689Skan * } 233169689Skan * </pre> 234169689Skan * <p> 235169689Skan * which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract 236169689Skan * type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share 237169689Skan * the same overloaded name), then instead of an object, you can just pass a function, so the above example can 238169689Skan * become even more simplified to: 239169689Skan * </p> 240169689Skan * <pre> 241169689Skan * var task = new TimerTask(function() { print("Hello World!") }) 242169689Skan * </pre> 243169689Skan * <p> 244169689Skan * Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors 245169689Skan * that take some arguments, you can invoke those simply by specifying the arguments after the initial 246169689Skan * implementation object or function. 247169689Skan * </p> 248169689Skan * <p>The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, 249169689Skan * you can just pass in a function object, and Nashorn will know what you meant: 250169689Skan * </p> 251169689Skan * <pre> 252169689Skan * var timer = new Java.type("java.util.Timer") 253169689Skan * timer.schedule(function() { print("Hello World!") }) 254169689Skan * </pre> 255169689Skan * <p> 256169689Skan * Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a 257169689Skan * {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In 258169689Skan * this usage though, you can't use non-default constructors; the type must be either an interface, or must have a 259169689Skan * protected or public no-arg constructor. 260169689Skan * </p> 261169689Skan * <p> 262169689Skan * You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)} 263169689Skan * method. 264169689Skan * </p> 265169689Skan * <p><b>Accessing static members</b></p> 266169689Skan * Examples: 267169689Skan * <pre> 268169689Skan * var File = Java.type("java.io.File") 269169689Skan * var pathSep = File.pathSeparator 270169689Skan * var tmpFile1 = File.createTempFile("abcdefg", ".tmp") 271169689Skan * var tmpFile2 = File.createTempFile("abcdefg", ".tmp", new File("/tmp")) 272169689Skan * </pre> 273169689Skan * Actually, you can even assign static methods to variables, so the above example can be rewritten as: 274169689Skan * <pre> 275169689Skan * var File = Java.type("java.io.File") 276169689Skan * var createTempFile = File.createTempFile 277169689Skan * var tmpFile1 = createTempFile("abcdefg", ".tmp") 278169689Skan * var tmpFile2 = createTempFile("abcdefg", ".tmp", new File("/tmp")) 279169689Skan * </pre> 280169689Skan * If you need to access the actual {@code java.lang.Class} object for the type, you can use the {@code class} 281169689Skan * property on the object representing the type: 282169689Skan * <pre> 283169689Skan * var File = Java.type("java.io.File") 284169689Skan * var someFile = new File("blah") 285169689Skan * print(File.class === someFile.getClass()) // prints true 286169689Skan * </pre> 287169689Skan * Of course, you can also use the {@code getClass()} method or its equivalent {@code class} property on any 288169689Skan * instance of the class. Other way round, you can use the synthetic {@code static} property on any 289169689Skan * {@code java.lang.Class} object to retrieve its type-representing object: 290169689Skan * <pre> 291169689Skan * var File = Java.type("java.io.File") 292169689Skan * print(File.class.static === File) // prints true 293169689Skan * </pre> 294169689Skan * <p><b>{@code instanceof} operator</b></p> 295169689Skan * The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects: 296169689Skan * <pre> 297169689Skan * var File = Java.type("java.io.File") 298169689Skan * var aFile = new File("foo") 299169689Skan * print(aFile instanceof File) // prints true 300169689Skan * print(aFile instanceof File.class) // prints false - Class objects aren't type objects. 301169689Skan * </pre> 302169689Skan * @param self not used 303169689Skan * @param objTypeName the object whose JS string value represents the type name. You can use names of primitive Java 304169689Skan * types to obtain representations of them, and you can use trailing square brackets to represent Java array types. 305169689Skan * @return the object representing the named type 306169689Skan * @throws ClassNotFoundException if the class is not found 307169689Skan */ 308169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 309169689Skan public static Object type(final Object self, final Object objTypeName) throws ClassNotFoundException { 310169689Skan return type(objTypeName); 311169689Skan } 312169689Skan 313169689Skan private static StaticClass type(final Object objTypeName) throws ClassNotFoundException { 314169689Skan return StaticClass.forClass(type(JSType.toString(objTypeName))); 315169689Skan } 316169689Skan 317169689Skan private static Class<?> type(final String typeName) throws ClassNotFoundException { 318169689Skan if (typeName.endsWith("[]")) { 319169689Skan return arrayType(typeName); 320169689Skan } 321169689Skan 322169689Skan return simpleType(typeName); 323169689Skan } 324169689Skan 325169689Skan /** 326169689Skan * Returns name of a java type {@link StaticClass}. 327169689Skan * @param self not used 328169689Skan * @param type the type whose name is returned 329169689Skan * @return name of the given type 330169689Skan */ 331169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 332169689Skan public static Object typeName(final Object self, final Object type) { 333169689Skan if (type instanceof StaticClass) { 334169689Skan return ((StaticClass)type).getRepresentedClass().getName(); 335169689Skan } else if (type instanceof Class) { 336169689Skan return ((Class<?>)type).getName(); 337169689Skan } else { 338169689Skan return UNDEFINED; 339169689Skan } 340169689Skan } 341169689Skan 342169689Skan /** 343169689Skan * Given a script object and a Java type, converts the script object into the desired Java type. Currently it 344169689Skan * performs shallow creation of Java arrays, as well as wrapping of objects in Lists, Dequeues, Queues, 345169689Skan * and Collections. Example: 346169689Skan * <pre> 347169689Skan * var anArray = [1, "13", false] 348169689Skan * var javaIntArray = Java.to(anArray, "int[]") 349169689Skan * print(javaIntArray[0]) // prints 1 350169689Skan * print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion 351169689Skan * print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion 352169689Skan * </pre> 353169689Skan * @param self not used 354169689Skan * @param obj the script object. Can be null. 355169689Skan * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java 356169689Skan * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be 357169689Skan * omitted). 358169689Skan * @return a Java object whose value corresponds to the original script object's value. Specifically, for array 359169689Skan * target types, returns a Java array of the same type with contents converted to the array's component type. 360169689Skan * Converts recursively when the target type is multidimensional array. For {@link List}, {@link Deque}, 361169689Skan * {@link Queue}, or {@link Collection}, returns a live wrapper around the object, see {@link ListAdapter} for 362169689Skan * details. Returns null if obj is null. 363169689Skan * @throws ClassNotFoundException if the class described by objType is not found 364169689Skan */ 365169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 366169689Skan public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException { 367169689Skan if (obj == null) { 368169689Skan return null; 369169689Skan } 370169689Skan 371169689Skan if (!(obj instanceof ScriptObject) && !(obj instanceof JSObject)) { 372169689Skan throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); 373169689Skan } 374169689Skan 375169689Skan final Class<?> targetClass; 376169689Skan if(objType == UNDEFINED) { 377169689Skan targetClass = Object[].class; 378169689Skan } else { 379169689Skan final StaticClass targetType; 380169689Skan if(objType instanceof StaticClass) { 381169689Skan targetType = (StaticClass)objType; 382169689Skan } else { 383169689Skan targetType = type(objType); 384169689Skan } 385169689Skan targetClass = targetType.getRepresentedClass(); 386169689Skan } 387169689Skan 388169689Skan if(targetClass.isArray()) { 389169689Skan return JSType.toJavaArray(obj, targetClass.getComponentType()); 390169689Skan } 391169689Skan 392169689Skan if (targetClass == List.class || targetClass == Deque.class || targetClass == Queue.class || targetClass == Collection.class) { 393169689Skan return ListAdapter.create(obj); 394169689Skan } 395169689Skan 396169689Skan throw typeError("unsupported.java.to.type", targetClass.getName()); 397169689Skan } 398169689Skan 399169689Skan /** 400169689Skan * Given a Java array or {@link Collection}, returns a JavaScript array with a shallow copy of its contents. Note 401169689Skan * that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you 402169689Skan * need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will 403169689Skan * want to use this method. Example: 404169689Skan * <pre> 405169689Skan * var File = Java.type("java.io.File") 406169689Skan * var listHomeDir = new File("~").listFiles() 407169689Skan * var jsListHome = Java.from(listHomeDir) 408169689Skan * var jpegModifiedDates = jsListHome 409169689Skan * .filter(function(val) { return val.getName().endsWith(".jpg") }) 410169689Skan * .map(function(val) { return val.lastModified() }) 411169689Skan * </pre> 412169689Skan * @param self not used 413169689Skan * @param objArray the java array or collection. Can be null. 414169689Skan * @return a JavaScript array with the copy of Java array's or collection's contents. Returns null if objArray is 415169689Skan * null. 416169689Skan */ 417169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 418169689Skan public static NativeArray from(final Object self, final Object objArray) { 419169689Skan if (objArray == null) { 420169689Skan return null; 421169689Skan } else if (objArray instanceof Collection) { 422169689Skan return new NativeArray(((Collection<?>)objArray).toArray()); 423169689Skan } else if (objArray instanceof Object[]) { 424169689Skan return new NativeArray(((Object[])objArray).clone()); 425169689Skan } else if (objArray instanceof int[]) { 426169689Skan return new NativeArray(((int[])objArray).clone()); 427169689Skan } else if (objArray instanceof double[]) { 428169689Skan return new NativeArray(((double[])objArray).clone()); 429169689Skan } else if (objArray instanceof long[]) { 430169689Skan return new NativeArray(((long[])objArray).clone()); 431169689Skan } else if (objArray instanceof byte[]) { 432169689Skan return new NativeArray(copyArray((byte[])objArray)); 433169689Skan } else if (objArray instanceof short[]) { 434169689Skan return new NativeArray(copyArray((short[])objArray)); 435169689Skan } else if (objArray instanceof char[]) { 436169689Skan return new NativeArray(copyArray((char[])objArray)); 437169689Skan } else if (objArray instanceof float[]) { 438169689Skan return new NativeArray(copyArray((float[])objArray)); 439169689Skan } else if (objArray instanceof boolean[]) { 440169689Skan return new NativeArray(copyArray((boolean[])objArray)); 441169689Skan } 442169689Skan 443169689Skan throw typeError("cant.convert.to.javascript.array", objArray.getClass().getName()); 444169689Skan } 445169689Skan 446169689Skan private static int[] copyArray(final byte[] in) { 447169689Skan final int[] out = new int[in.length]; 448169689Skan for(int i = 0; i < in.length; ++i) { 449169689Skan out[i] = in[i]; 450169689Skan } 451169689Skan return out; 452169689Skan } 453169689Skan 454169689Skan private static int[] copyArray(final short[] in) { 455169689Skan final int[] out = new int[in.length]; 456169689Skan for(int i = 0; i < in.length; ++i) { 457169689Skan out[i] = in[i]; 458169689Skan } 459169689Skan return out; 460169689Skan } 461169689Skan 462169689Skan private static int[] copyArray(final char[] in) { 463169689Skan final int[] out = new int[in.length]; 464169689Skan for(int i = 0; i < in.length; ++i) { 465169689Skan out[i] = in[i]; 466169689Skan } 467169689Skan return out; 468169689Skan } 469169689Skan 470169689Skan private static double[] copyArray(final float[] in) { 471169689Skan final double[] out = new double[in.length]; 472169689Skan for(int i = 0; i < in.length; ++i) { 473169689Skan out[i] = in[i]; 474169689Skan } 475169689Skan return out; 476169689Skan } 477169689Skan 478169689Skan private static Object[] copyArray(final boolean[] in) { 479169689Skan final Object[] out = new Object[in.length]; 480169689Skan for(int i = 0; i < in.length; ++i) { 481169689Skan out[i] = in[i]; 482169689Skan } 483169689Skan return out; 484169689Skan } 485169689Skan 486169689Skan private static Class<?> simpleType(final String typeName) throws ClassNotFoundException { 487169689Skan final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName); 488169689Skan if(primClass != null) { 489169689Skan return primClass; 490169689Skan } 491169689Skan final Context ctx = Global.getThisContext(); 492169689Skan try { 493169689Skan return ctx.findClass(typeName); 494169689Skan } catch(final ClassNotFoundException e) { 495169689Skan // The logic below compensates for a frequent user error - when people use dot notation to separate inner 496169689Skan // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic 497169689Skan // below will try alternative class names, replacing dots at the end of the name with dollar signs. 498169689Skan final StringBuilder nextName = new StringBuilder(typeName); 499169689Skan int lastDot = nextName.length(); 500169689Skan for(;;) { 501169689Skan lastDot = nextName.lastIndexOf(".", lastDot - 1); 502169689Skan if(lastDot == -1) { 503169689Skan // Exhausted the search space, class not found - rethrow the original exception. 504169689Skan throw e; 505169689Skan } 506169689Skan nextName.setCharAt(lastDot, '$'); 507169689Skan try { 508169689Skan return ctx.findClass(nextName.toString()); 509169689Skan } catch(final ClassNotFoundException cnfe) { 510169689Skan // Intentionally ignored, so the loop retries with the next name 511169689Skan } 512169689Skan } 513169689Skan } 514169689Skan 515169689Skan } 516169689Skan 517169689Skan private static Class<?> arrayType(final String typeName) throws ClassNotFoundException { 518169689Skan return Array.newInstance(type(typeName.substring(0, typeName.length() - 2)), 0).getClass(); 519169689Skan } 520169689Skan 521169689Skan /** 522169689Skan * Returns a type object for a subclass of the specified Java class (or implementation of the specified interface) 523169689Skan * that acts as a script-to-Java adapter for it. See {@link #type(Object, Object)} for a discussion of type objects, 524169689Skan * and see {@link JavaAdapterFactory} for details on script-to-Java adapters. Note that you can also implement 525169689Skan * interfaces and subclass abstract classes using {@code new} operator on a type object for an interface or abstract 526169689Skan * class. However, to extend a non-abstract class, you will have to use this method. Example: 527169689Skan * <pre> 528169689Skan * var ArrayList = Java.type("java.util.ArrayList") 529169689Skan * var ArrayListExtender = Java.extend(ArrayList) 530169689Skan * var printSizeInvokedArrayList = new ArrayListExtender() { 531169689Skan * size: function() { print("size invoked!"); } 532169689Skan * } 533169689Skan * var printAddInvokedArrayList = new ArrayListExtender() { 534169689Skan * add: function(x, y) { 535169689Skan * if(typeof(y) === "undefined") { 536169689Skan * print("add(e) invoked!"); 537169689Skan * } else { 538169689Skan * print("add(i, e) invoked!"); 539169689Skan * } 540169689Skan * } 541169689Skan * </pre> 542169689Skan * We can see several important concepts in the above example: 543169689Skan * <ul> 544169689Skan * <li>Every specified list of Java types will have one extender subclass in Nashorn per caller protection domain - 545169689Skan * repeated invocations of {@code extend} for the same list of types for scripts same protection domain will yield 546169689Skan * the same extender type. It's a generic adapter that delegates to whatever JavaScript functions its implementation 547169689Skan * object has on a per-instance basis.</li> 548169689Skan * <li>If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter 549169689Skan * must be prepared to deal with all overloads.</li> 550169689Skan * <li>To invoke super methods from adapters, call them on the adapter instance prefixing them with {@code super$}, 551169689Skan * or use the special {@link #_super(Object, Object) super-adapter}.</li> 552169689Skan * <li>It is also possible to specify an ordinary JavaScript object as the last argument to {@code extend}. In that 553169689Skan * case, it is treated as a class-level override. {@code extend} will return an extender class where all instances 554169689Skan * will have the methods implemented by functions on that object, just as if that object were passed as the last 555169689Skan * argument to their constructor. Example: 556169689Skan * <pre> 557169689Skan * var Runnable = Java.type("java.lang.Runnable") 558169689Skan * var R1 = Java.extend(Runnable, { 559169689Skan * run: function() { 560169689Skan * print("R1.run() invoked!") 561169689Skan * } 562169689Skan * }) 563169689Skan * var r1 = new R1 564169689Skan * var t = new java.lang.Thread(r1) 565169689Skan * t.start() 566169689Skan * t.join() 567169689Skan * </pre> 568169689Skan * As you can see, you don't have to pass any object when you create a new instance of {@code R1} as its 569169689Skan * {@code run()} function was defined already when extending the class. If you also want to add instance-level 570169689Skan * overrides on these objects, you will have to repeatedly use {@code extend()} to subclass the class-level adapter. 571169689Skan * For such adapters, the order of precedence is instance-level method, class-level method, superclass method, or 572169689Skan * {@code UnsupportedOperationException} if the superclass method is abstract. If we continue our previous example: 573169689Skan * <pre> 574169689Skan * var R2 = Java.extend(R1); 575169689Skan * var r2 = new R2(function() { print("r2.run() invoked!") }) 576169689Skan * r2.run() 577169689Skan * </pre> 578169689Skan * We'll see it'll print {@code "r2.run() invoked!"}, thus overriding on instance-level the class-level behavior. 579169689Skan * Note that you must use {@code Java.extend} to explicitly create an instance-override adapter class from a 580169689Skan * class-override adapter class, as the class-override adapter class is no longer abstract. 581169689Skan * </li> 582169689Skan * </ul> 583169689Skan * @param self not used 584169689Skan * @param types the original types. The caller must pass at least one Java type object of class {@link StaticClass} 585169689Skan * representing either a public interface or a non-final public class with at least one public or protected 586169689Skan * constructor. If more than one type is specified, at most one can be a class and the rest have to be interfaces. 587169689Skan * Invoking the method twice with exactly the same types in the same order - in absence of class-level overrides - 588169689Skan * will return the same adapter class, any reordering of types or even addition or removal of redundant types (i.e. 589169689Skan * interfaces that other types in the list already implement/extend, or {@code java.lang.Object} in a list of types 590169689Skan * consisting purely of interfaces) will result in a different adapter class, even though those adapter classes are 591169689Skan * functionally identical; we deliberately don't want to incur the additional processing cost of canonicalizing type 592169689Skan * lists. As a special case, the last argument can be a {@code ScriptObject} instead of a type. In this case, a 593169689Skan * separate adapter class is generated - new one for each invocation - that will use the passed script object as its 594169689Skan * implementation for all instances. Instances of such adapter classes can then be created without passing another 595169689Skan * script object in the constructor, as the class has a class-level behavior defined by the script object. However, 596169689Skan * you can still pass a script object (or if it's a SAM type, a function) to the constructor to provide further 597169689Skan * instance-level overrides. 598169689Skan * 599169689Skan * @return a new {@link StaticClass} that represents the adapter for the original types. 600169689Skan */ 601169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 602169689Skan public static Object extend(final Object self, final Object... types) { 603169689Skan if(types == null || types.length == 0) { 604169689Skan throw typeError("extend.expects.at.least.one.argument"); 605169689Skan } 606169689Skan final int l = types.length; 607169689Skan final int typesLen; 608169689Skan final ScriptObject classOverrides; 609169689Skan if(types[l - 1] instanceof ScriptObject) { 610169689Skan classOverrides = (ScriptObject)types[l - 1]; 611169689Skan typesLen = l - 1; 612169689Skan if(typesLen == 0) { 613169689Skan throw typeError("extend.expects.at.least.one.type.argument"); 614169689Skan } 615169689Skan } else { 616169689Skan classOverrides = null; 617169689Skan typesLen = l; 618169689Skan } 619169689Skan final Class<?>[] stypes = new Class<?>[typesLen]; 620169689Skan try { 621169689Skan for(int i = 0; i < typesLen; ++i) { 622169689Skan stypes[i] = ((StaticClass)types[i]).getRepresentedClass(); 623169689Skan } 624169689Skan } catch(final ClassCastException e) { 625169689Skan throw typeError("extend.expects.java.types"); 626169689Skan } 627169689Skan // Note that while the public API documentation claims self is not used, we actually use it. 628169689Skan // ScriptFunction.findCallMethod will bind the lookup object into it, and we can then use that lookup when 629169689Skan // requesting the adapter class. Note that if Java.extend is invoked with no lookup object, it'll pass the 630169689Skan // public lookup which'll result in generation of a no-permissions adapter. A typical situation this can happen 631169689Skan // is when the extend function is bound. 632169689Skan final MethodHandles.Lookup lookup; 633169689Skan if(self instanceof MethodHandles.Lookup) { 634169689Skan lookup = (MethodHandles.Lookup)self; 635169689Skan } else { 636169689Skan lookup = MethodHandles.publicLookup(); 637169689Skan } 638169689Skan return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides, lookup); 639169689Skan } 640169689Skan 641169689Skan /** 642169689Skan * When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java 643169689Skan * adapter), returns an object that can be used to invoke superclass methods on that object. E.g.: 644169689Skan * <pre> 645169689Skan * var cw = new FilterWriterAdapter(sw) { 646169689Skan * write: function(s, off, len) { 647169689Skan * s = capitalize(s, off, len) 648169689Skan * cw_super.write(s, 0, s.length()) 649169689Skan * } 650169689Skan * } 651169689Skan * var cw_super = Java.super(cw) 652169689Skan * </pre> 653169689Skan * @param self the {@code Java} object itself - not used. 654169689Skan * @param adapter the original Java adapter instance for which the super adapter is created. 655169689Skan * @return a super adapter for the original adapter 656169689Skan */ 657169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super") 658169689Skan public static Object _super(final Object self, final Object adapter) { 659169689Skan return Bootstrap.createSuperAdapter(adapter); 660169689Skan } 661169689Skan 662169689Skan /** 663169689Skan * Returns an object that is compatible with Java JSON libraries expectations; namely, that if it itself, or any 664169689Skan * object transitively reachable through it is a JavaScript array, then such objects will be exposed as 665169689Skan * {@link JSObject} that also implements the {@link List} interface for exposing the array elements. An explicit 666169689Skan * API is required as otherwise Nashorn exposes all objects externally as {@link JSObject}s that also implement the 667169689Skan * {@link Map} interface instead. By using this method, arrays will be exposed as {@link List}s and all other 668169689Skan * objects as {@link Map}s. 669169689Skan * @param self not used 670169689Skan * @param obj the object to be exposed in a Java JSON library compatible manner. 671169689Skan * @return a wrapper around the object that will enforce Java JSON library compatible exposure. 672169689Skan */ 673169689Skan @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) 674169689Skan public static Object asJSONCompatible(final Object self, final Object obj) { 675169689Skan return ScriptObjectMirror.wrapAsJSONCompatible(obj, Context.getGlobal()); 676169689Skan } 677169689Skan} 678169689Skan