1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.objects;
  27 
  28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  30 
  31 import java.lang.invoke.MethodHandles;
  32 import java.lang.reflect.Array;
  33 import java.util.Collection;
  34 import java.util.Deque;
  35 import java.util.List;
  36 import java.util.Map;
  37 import java.util.Queue;
  38 import jdk.internal.dynalink.beans.StaticClass;
  39 import jdk.internal.dynalink.support.TypeUtilities;
  40 import jdk.nashorn.api.scripting.JSObject;
  41 import jdk.nashorn.api.scripting.ScriptObjectMirror;
  42 import jdk.nashorn.internal.objects.annotations.Attribute;
  43 import jdk.nashorn.internal.objects.annotations.Function;
  44 import jdk.nashorn.internal.objects.annotations.ScriptClass;
  45 import jdk.nashorn.internal.objects.annotations.Where;
  46 import jdk.nashorn.internal.runtime.Context;
  47 import jdk.nashorn.internal.runtime.JSType;
  48 import jdk.nashorn.internal.runtime.ListAdapter;
  49 import jdk.nashorn.internal.runtime.PropertyMap;
  50 import jdk.nashorn.internal.runtime.ScriptFunction;
  51 import jdk.nashorn.internal.runtime.ScriptObject;
  52 import jdk.nashorn.internal.runtime.ScriptRuntime;
  53 import jdk.nashorn.internal.runtime.linker.Bootstrap;
  54 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
  55 
  56 /**
  57  * This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This
  58  * object acts as the API entry point to Java platform specific functionality, dealing with creating new instances of
  59  * Java classes, subclassing Java classes, implementing Java interfaces, converting between Java arrays and ECMAScript
  60  * arrays, and so forth.
  61  */
  62 @ScriptClass("Java")
  63 public final class NativeJava {
  64 
  65     // initialized by nasgen
  66     @SuppressWarnings("unused")
  67     private static PropertyMap $nasgenmap$;
  68 
  69     private NativeJava() {
  70         // don't create me
  71         throw new UnsupportedOperationException();
  72     }
  73 
  74     /**
  75      * Returns true if the specified object is a Java type object, that is an instance of {@link StaticClass}.
  76      * @param self not used
  77      * @param type the object that is checked if it is a type object or not
  78      * @return tells whether given object is a Java type object or not.
  79      * @see #type(Object, Object)
  80      */
  81     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
  82     public static boolean isType(final Object self, final Object type) {
  83         return type instanceof StaticClass;
  84     }
  85 
  86     /**
  87      * Returns synchronized wrapper version of the given ECMAScript function.
  88      * @param self not used
  89      * @param func the ECMAScript function whose synchronized version is returned.
  90      * @param obj the object (i.e, lock) on which the function synchronizes.
  91      * @return synchronized wrapper version of the given ECMAScript function.
  92      */
  93     @Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
  94     public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
  95         if (func instanceof ScriptFunction) {
  96             return ((ScriptFunction)func).makeSynchronizedFunction(obj);
  97         }
  98 
  99         throw typeError("not.a.function", ScriptRuntime.safeToString(func));
 100     }
 101 
 102     /**
 103      * Returns true if the specified object is a Java method.
 104      * @param self not used
 105      * @param obj the object that is checked if it is a Java method object or not
 106      * @return tells whether given object is a Java method object or not.
 107      */
 108     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 109     public static boolean isJavaMethod(final Object self, final Object obj) {
 110         return Bootstrap.isDynamicMethod(obj);
 111     }
 112 
 113     /**
 114      * Returns true if the specified object is a java function (but not script function)
 115      * @param self not used
 116      * @param obj the object that is checked if it is a Java function or not
 117      * @return tells whether given object is a Java function or not
 118      */
 119     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 120     public static boolean isJavaFunction(final Object self, final Object obj) {
 121         return Bootstrap.isCallable(obj) && !(obj instanceof ScriptFunction);
 122     }
 123 
 124     /**
 125      * Returns true if the specified object is a Java object but not a script object
 126      * @param self not used
 127      * @param obj the object that is checked
 128      * @return tells whether given object is a Java object but not a script object
 129      */
 130     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 131     public static boolean isJavaObject(final Object self, final Object obj) {
 132         return obj != null && !(obj instanceof ScriptObject);
 133     }
 134 
 135     /**
 136      * Returns true if the specified object is a ECMAScript object, that is an instance of {@link ScriptObject}.
 137      * @param self not used
 138      * @param obj the object that is checked if it is a ECMAScript object or not
 139      * @return tells whether given object is a ECMAScript object or not.
 140      */
 141     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 142     public static boolean isScriptObject(final Object self, final Object obj) {
 143         return obj instanceof ScriptObject;
 144     }
 145 
 146     /**
 147      * Returns true if the specified object is a ECMAScript function, that is an instance of {@link ScriptFunction}.
 148      * @param self not used
 149      * @param obj the object that is checked if it is a ECMAScript function or not
 150      * @return tells whether given object is a ECMAScript function or not.
 151      */
 152     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 153     public static boolean isScriptFunction(final Object self, final Object obj) {
 154         return obj instanceof ScriptFunction;
 155     }
 156 
 157     /**
 158      * <p>
 159      * Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects
 160      * used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are
 161      * the objects that you can use with the {@code new} operator to create new instances of the class as well as to
 162      * access static members of the class. In Nashorn, {@code Class} objects are just regular Java objects that aren't
 163      * treated specially. Instead of them, {@link StaticClass} instances - which we sometimes refer to as "Java type
 164      * objects" are used as constructors with the {@code new} operator, and they expose static fields, properties, and
 165      * methods. While this might seem confusing at first, it actually closely matches the Java language: you use a
 166      * different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is
 167      * distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the
 168      * properties of the type objects.
 169      * </p>
 170      * <p><b>Constructing Java objects</b></p>
 171      * Examples:
 172      * <pre>
 173      * var arrayListType = Java.type("java.util.ArrayList")
 174      * var intType = Java.type("int")
 175      * var stringArrayType = Java.type("java.lang.String[]")
 176      * var int2DArrayType = Java.type("int[][]")
 177      * </pre>
 178      * Note that the name of the type is always a string for a fully qualified name. You can use any of these types to
 179      * create new instances, e.g.:
 180      * <pre>
 181      * var anArrayList = new Java.type("java.util.ArrayList")
 182      * </pre>
 183      * or
 184      * <pre>
 185      * var ArrayList = Java.type("java.util.ArrayList")
 186      * var anArrayList = new ArrayList
 187      * var anArrayListWithSize = new ArrayList(16)
 188      * </pre>
 189      * In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $}
 190      * sign in the class name, or you can use the dot:
 191      * <pre>
 192      * var ftype = Java.type("java.awt.geom.Arc2D$Float")
 193      * </pre>
 194      * and
 195      * <pre>
 196      * var ftype = Java.type("java.awt.geom.Arc2D.Float")
 197      * </pre>
 198      * both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name
 199      * as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the
 200      * dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to
 201      * dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads
 202      * the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested
 203      * inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An
 204      * alternative way to access the inner class is as a property of the outer class:
 205      * <pre>
 206      * var arctype = Java.type("java.awt.geom.Arc2D")
 207      * var ftype = arctype.Float
 208      * </pre>
 209      * <p>
 210      * You can access both static and non-static inner classes. If you want to create an instance of a non-static
 211      * inner class, remember to pass an instance of its outer class as the first argument to the constructor.
 212      * </p>
 213      * <p>
 214      * If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is
 215      * applicable to any of its public or protected constructors, but inserting a JavaScript object with functions
 216      * properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the
 217      * JavaScript function will provide implementation for all overloads. E.g.:
 218      * </p>
 219      * <pre>
 220      * var TimerTask =  Java.type("java.util.TimerTask")
 221      * var task = new TimerTask({ run: function() { print("Hello World!") } })
 222      * </pre>
 223      * <p>
 224      * Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to
 225      * invoking the constructor and passing the argument to it, so you can write the above example also as:
 226      * </p>
 227      * <pre>
 228      * var task = new TimerTask {
 229      *     run: function() {
 230      *       print("Hello World!")
 231      *     }
 232      * }
 233      * </pre>
 234      * <p>
 235      * which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract
 236      * type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share
 237      * the same overloaded name), then instead of an object, you can just pass a function, so the above example can
 238      * become even more simplified to:
 239      * </p>
 240      * <pre>
 241      * var task = new TimerTask(function() { print("Hello World!") })
 242      * </pre>
 243      * <p>
 244      * Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors
 245      * that take some arguments, you can invoke those simply by specifying the arguments after the initial
 246      * implementation object or function.
 247      * </p>
 248      * <p>The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type,
 249      * you can just pass in a function object, and Nashorn will know what you meant:
 250      * </p>
 251      * <pre>
 252      * var timer = new Java.type("java.util.Timer")
 253      * timer.schedule(function() { print("Hello World!") })
 254      * </pre>
 255      * <p>
 256      * Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a
 257      * {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In
 258      * this usage though, you can't use non-default constructors; the type must be either an interface, or must have a
 259      * protected or public no-arg constructor.
 260      * </p>
 261      * <p>
 262      * You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)}
 263      * method.
 264      * </p>
 265      * <p><b>Accessing static members</b></p>
 266      * Examples:
 267      * <pre>
 268      * var File = Java.type("java.io.File")
 269      * var pathSep = File.pathSeparator
 270      * var tmpFile1 = File.createTempFile("abcdefg", ".tmp")
 271      * var tmpFile2 = File.createTempFile("abcdefg", ".tmp", new File("/tmp"))
 272      * </pre>
 273      * Actually, you can even assign static methods to variables, so the above example can be rewritten as:
 274      * <pre>
 275      * var File = Java.type("java.io.File")
 276      * var createTempFile = File.createTempFile
 277      * var tmpFile1 = createTempFile("abcdefg", ".tmp")
 278      * var tmpFile2 = createTempFile("abcdefg", ".tmp", new File("/tmp"))
 279      * </pre>
 280      * If you need to access the actual {@code java.lang.Class} object for the type, you can use the {@code class}
 281      * property on the object representing the type:
 282      * <pre>
 283      * var File = Java.type("java.io.File")
 284      * var someFile = new File("blah")
 285      * print(File.class === someFile.getClass()) // prints true
 286      * </pre>
 287      * Of course, you can also use the {@code getClass()} method or its equivalent {@code class} property on any
 288      * instance of the class. Other way round, you can use the synthetic {@code static} property on any
 289      * {@code java.lang.Class} object to retrieve its type-representing object:
 290      * <pre>
 291      * var File = Java.type("java.io.File")
 292      * print(File.class.static === File) // prints true
 293      * </pre>
 294      * <p><b>{@code instanceof} operator</b></p>
 295      * The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects:
 296      * <pre>
 297      * var File = Java.type("java.io.File")
 298      * var aFile = new File("foo")
 299      * print(aFile instanceof File) // prints true
 300      * print(aFile instanceof File.class) // prints false - Class objects aren't type objects.
 301      * </pre>
 302      * @param self not used
 303      * @param objTypeName the object whose JS string value represents the type name. You can use names of primitive Java
 304      * types to obtain representations of them, and you can use trailing square brackets to represent Java array types.
 305      * @return the object representing the named type
 306      * @throws ClassNotFoundException if the class is not found
 307      */
 308     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 309     public static Object type(final Object self, final Object objTypeName) throws ClassNotFoundException {
 310         return type(objTypeName);
 311     }
 312 
 313     private static StaticClass type(final Object objTypeName) throws ClassNotFoundException {
 314         return StaticClass.forClass(type(JSType.toString(objTypeName)));
 315     }
 316 
 317     private static Class<?> type(final String typeName) throws ClassNotFoundException {
 318         if (typeName.endsWith("[]")) {
 319             return arrayType(typeName);
 320         }
 321 
 322         return simpleType(typeName);
 323     }
 324 
 325     /**
 326      * Returns name of a java type {@link StaticClass}.
 327      * @param self not used
 328      * @param type the type whose name is returned
 329      * @return name of the given type
 330      */
 331     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 332     public static Object typeName(final Object self, final Object type) {
 333         if (type instanceof StaticClass) {
 334             return ((StaticClass)type).getRepresentedClass().getName();
 335         } else if (type instanceof Class) {
 336             return ((Class<?>)type).getName();
 337         } else {
 338             return UNDEFINED;
 339         }
 340     }
 341 
 342     /**
 343      * Given a script object and a Java type, converts the script object into the desired Java type. Currently it
 344      * performs shallow creation of Java arrays, as well as wrapping of objects in Lists, Dequeues, Queues,
 345      * and Collections. Example:
 346      * <pre>
 347      * var anArray = [1, "13", false]
 348      * var javaIntArray = Java.to(anArray, "int[]")
 349      * print(javaIntArray[0]) // prints 1
 350      * print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
 351      * print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
 352      * </pre>
 353      * @param self not used
 354      * @param obj the script object. Can be null.
 355      * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java
 356      * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be
 357      * omitted).
 358      * @return a Java object whose value corresponds to the original script object's value. Specifically, for array
 359      * target types, returns a Java array of the same type with contents converted to the array's component type.
 360      * Converts recursively when the target type is multidimensional array. For {@link List}, {@link Deque},
 361      * {@link Queue}, or {@link Collection}, returns a live wrapper around the object, see {@link ListAdapter} for
 362      * details. Returns null if obj is null.
 363      * @throws ClassNotFoundException if the class described by objType is not found
 364      */
 365     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 366     public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException {
 367         if (obj == null) {
 368             return null;
 369         }
 370 
 371         if (!(obj instanceof ScriptObject) && !(obj instanceof JSObject)) {
 372             throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
 373         }
 374 
 375         final Class<?> targetClass;
 376         if(objType == UNDEFINED) {
 377             targetClass = Object[].class;
 378         } else {
 379             final StaticClass targetType;
 380             if(objType instanceof StaticClass) {
 381                 targetType = (StaticClass)objType;
 382             } else {
 383                 targetType = type(objType);
 384             }
 385             targetClass = targetType.getRepresentedClass();
 386         }
 387 
 388         if(targetClass.isArray()) {
 389             return JSType.toJavaArray(obj, targetClass.getComponentType());
 390         }
 391 
 392         if (targetClass == List.class || targetClass == Deque.class || targetClass == Queue.class || targetClass == Collection.class) {
 393             return ListAdapter.create(obj);
 394         }
 395 
 396         throw typeError("unsupported.java.to.type", targetClass.getName());
 397     }
 398 
 399     /**
 400      * Given a Java array or {@link Collection}, returns a JavaScript array with a shallow copy of its contents. Note
 401      * that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you
 402      * need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will
 403      * want to use this method. Example:
 404      * <pre>
 405      * var File = Java.type("java.io.File")
 406      * var listHomeDir = new File("~").listFiles()
 407      * var jsListHome = Java.from(listHomeDir)
 408      * var jpegModifiedDates = jsListHome
 409      *     .filter(function(val) { return val.getName().endsWith(".jpg") })
 410      *     .map(function(val) { return val.lastModified() })
 411      * </pre>
 412      * @param self not used
 413      * @param objArray the java array or collection. Can be null.
 414      * @return a JavaScript array with the copy of Java array's or collection's contents. Returns null if objArray is
 415      * null.
 416      */
 417     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 418     public static NativeArray from(final Object self, final Object objArray) {
 419         if (objArray == null) {
 420             return null;
 421         } else if (objArray instanceof Collection) {
 422             return new NativeArray(((Collection<?>)objArray).toArray());
 423         } else if (objArray instanceof Object[]) {
 424             return new NativeArray(((Object[])objArray).clone());
 425         } else if (objArray instanceof int[]) {
 426             return new NativeArray(((int[])objArray).clone());
 427         } else if (objArray instanceof double[]) {
 428             return new NativeArray(((double[])objArray).clone());
 429         } else if (objArray instanceof long[]) {
 430             return new NativeArray(((long[])objArray).clone());
 431         } else if (objArray instanceof byte[]) {
 432             return new NativeArray(copyArray((byte[])objArray));
 433         } else if (objArray instanceof short[]) {
 434             return new NativeArray(copyArray((short[])objArray));
 435         } else if (objArray instanceof char[]) {
 436             return new NativeArray(copyArray((char[])objArray));
 437         } else if (objArray instanceof float[]) {
 438             return new NativeArray(copyArray((float[])objArray));
 439         } else if (objArray instanceof boolean[]) {
 440             return new NativeArray(copyArray((boolean[])objArray));
 441         }
 442 
 443         throw typeError("cant.convert.to.javascript.array", objArray.getClass().getName());
 444     }
 445 
 446     private static int[] copyArray(final byte[] in) {
 447         final int[] out = new int[in.length];
 448         for(int i = 0; i < in.length; ++i) {
 449             out[i] = in[i];
 450         }
 451         return out;
 452     }
 453 
 454     private static int[] copyArray(final short[] in) {
 455         final int[] out = new int[in.length];
 456         for(int i = 0; i < in.length; ++i) {
 457             out[i] = in[i];
 458         }
 459         return out;
 460     }
 461 
 462     private static int[] copyArray(final char[] in) {
 463         final int[] out = new int[in.length];
 464         for(int i = 0; i < in.length; ++i) {
 465             out[i] = in[i];
 466         }
 467         return out;
 468     }
 469 
 470     private static double[] copyArray(final float[] in) {
 471         final double[] out = new double[in.length];
 472         for(int i = 0; i < in.length; ++i) {
 473             out[i] = in[i];
 474         }
 475         return out;
 476     }
 477 
 478     private static Object[] copyArray(final boolean[] in) {
 479         final Object[] out = new Object[in.length];
 480         for(int i = 0; i < in.length; ++i) {
 481             out[i] = in[i];
 482         }
 483         return out;
 484     }
 485 
 486     private static Class<?> simpleType(final String typeName) throws ClassNotFoundException {
 487         final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName);
 488         if(primClass != null) {
 489             return primClass;
 490         }
 491         final Context ctx = Global.getThisContext();
 492         try {
 493             return ctx.findClass(typeName);
 494         } catch(final ClassNotFoundException e) {
 495             // The logic below compensates for a frequent user error - when people use dot notation to separate inner
 496             // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic
 497             // below will try alternative class names, replacing dots at the end of the name with dollar signs.
 498             final StringBuilder nextName = new StringBuilder(typeName);
 499             int lastDot = nextName.length();
 500             for(;;) {
 501                 lastDot = nextName.lastIndexOf(".", lastDot - 1);
 502                 if(lastDot == -1) {
 503                     // Exhausted the search space, class not found - rethrow the original exception.
 504                     throw e;
 505                 }
 506                 nextName.setCharAt(lastDot, '$');
 507                 try {
 508                     return ctx.findClass(nextName.toString());
 509                 } catch(final ClassNotFoundException cnfe) {
 510                     // Intentionally ignored, so the loop retries with the next name
 511                 }
 512             }
 513         }
 514 
 515     }
 516 
 517     private static Class<?> arrayType(final String typeName) throws ClassNotFoundException {
 518         return Array.newInstance(type(typeName.substring(0, typeName.length() - 2)), 0).getClass();
 519     }
 520 
 521     /**
 522      * Returns a type object for a subclass of the specified Java class (or implementation of the specified interface)
 523      * that acts as a script-to-Java adapter for it. See {@link #type(Object, Object)} for a discussion of type objects,
 524      * and see {@link JavaAdapterFactory} for details on script-to-Java adapters. Note that you can also implement
 525      * interfaces and subclass abstract classes using {@code new} operator on a type object for an interface or abstract
 526      * class. However, to extend a non-abstract class, you will have to use this method. Example:
 527      * <pre>
 528      * var ArrayList = Java.type("java.util.ArrayList")
 529      * var ArrayListExtender = Java.extend(ArrayList)
 530      * var printSizeInvokedArrayList = new ArrayListExtender() {
 531      *     size: function() { print("size invoked!"); }
 532      * }
 533      * var printAddInvokedArrayList = new ArrayListExtender() {
 534      *     add: function(x, y) {
 535      *       if(typeof(y) === "undefined") {
 536      *           print("add(e) invoked!");
 537      *       } else {
 538      *           print("add(i, e) invoked!");
 539      *       }
 540      * }
 541      * </pre>
 542      * We can see several important concepts in the above example:
 543      * <ul>
 544      * <li>Every specified list of Java types will have one extender subclass in Nashorn per caller protection domain -
 545      * repeated invocations of {@code extend} for the same list of types for scripts same protection domain will yield
 546      * the same extender type. It's a generic adapter that delegates to whatever JavaScript functions its implementation
 547      * object has on a per-instance basis.</li>
 548      * <li>If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter
 549      * must be prepared to deal with all overloads.</li>
 550      * <li>To invoke super methods from adapters, call them on the adapter instance prefixing them with {@code super$},
 551      * or use the special {@link #_super(Object, Object) super-adapter}.</li>
 552      * <li>It is also possible to specify an ordinary JavaScript object as the last argument to {@code extend}. In that
 553      * case, it is treated as a class-level override. {@code extend} will return an extender class where all instances
 554      * will have the methods implemented by functions on that object, just as if that object were passed as the last
 555      * argument to their constructor. Example:
 556      * <pre>
 557      * var Runnable = Java.type("java.lang.Runnable")
 558      * var R1 = Java.extend(Runnable, {
 559      *     run: function() {
 560      *         print("R1.run() invoked!")
 561      *     }
 562      * })
 563      * var r1 = new R1
 564      * var t = new java.lang.Thread(r1)
 565      * t.start()
 566      * t.join()
 567      * </pre>
 568      * As you can see, you don't have to pass any object when you create a new instance of {@code R1} as its
 569      * {@code run()} function was defined already when extending the class. If you also want to add instance-level
 570      * overrides on these objects, you will have to repeatedly use {@code extend()} to subclass the class-level adapter.
 571      * For such adapters, the order of precedence is instance-level method, class-level method, superclass method, or
 572      * {@code UnsupportedOperationException} if the superclass method is abstract. If we continue our previous example:
 573      * <pre>
 574      * var R2 = Java.extend(R1);
 575      * var r2 = new R2(function() { print("r2.run() invoked!") })
 576      * r2.run()
 577      * </pre>
 578      * We'll see it'll print {@code "r2.run() invoked!"}, thus overriding on instance-level the class-level behavior.
 579      * Note that you must use {@code Java.extend} to explicitly create an instance-override adapter class from a
 580      * class-override adapter class, as the class-override adapter class is no longer abstract.
 581      * </li>
 582      * </ul>
 583      * @param self not used
 584      * @param types the original types. The caller must pass at least one Java type object of class {@link StaticClass}
 585      * representing either a public interface or a non-final public class with at least one public or protected
 586      * constructor. If more than one type is specified, at most one can be a class and the rest have to be interfaces.
 587      * Invoking the method twice with exactly the same types in the same order - in absence of class-level overrides -
 588      * will return the same adapter class, any reordering of types or even addition or removal of redundant types (i.e.
 589      * interfaces that other types in the list already implement/extend, or {@code java.lang.Object} in a list of types
 590      * consisting purely of interfaces) will result in a different adapter class, even though those adapter classes are
 591      * functionally identical; we deliberately don't want to incur the additional processing cost of canonicalizing type
 592      * lists. As a special case, the last argument can be a {@code ScriptObject} instead of a type. In this case, a
 593      * separate adapter class is generated - new one for each invocation - that will use the passed script object as its
 594      * implementation for all instances. Instances of such adapter classes can then be created without passing another
 595      * script object in the constructor, as the class has a class-level behavior defined by the script object. However,
 596      * you can still pass a script object (or if it's a SAM type, a function) to the constructor to provide further
 597      * instance-level overrides.
 598      *
 599      * @return a new {@link StaticClass} that represents the adapter for the original types.
 600      */
 601     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 602     public static Object extend(final Object self, final Object... types) {
 603         if(types == null || types.length == 0) {
 604             throw typeError("extend.expects.at.least.one.argument");
 605         }
 606         final int l = types.length;
 607         final int typesLen;
 608         final ScriptObject classOverrides;
 609         if(types[l - 1] instanceof ScriptObject) {
 610             classOverrides = (ScriptObject)types[l - 1];
 611             typesLen = l - 1;
 612             if(typesLen == 0) {
 613                 throw typeError("extend.expects.at.least.one.type.argument");
 614             }
 615         } else {
 616             classOverrides = null;
 617             typesLen = l;
 618         }
 619         final Class<?>[] stypes = new Class<?>[typesLen];
 620         try {
 621             for(int i = 0; i < typesLen; ++i) {
 622                 stypes[i] = ((StaticClass)types[i]).getRepresentedClass();
 623             }
 624         } catch(final ClassCastException e) {
 625             throw typeError("extend.expects.java.types");
 626         }
 627         // Note that while the public API documentation claims self is not used, we actually use it.
 628         // ScriptFunction.findCallMethod will bind the lookup object into it, and we can then use that lookup when
 629         // requesting the adapter class. Note that if Java.extend is invoked with no lookup object, it'll pass the
 630         // public lookup which'll result in generation of a no-permissions adapter. A typical situation this can happen
 631         // is when the extend function is bound.
 632         final MethodHandles.Lookup lookup;
 633         if(self instanceof MethodHandles.Lookup) {
 634             lookup = (MethodHandles.Lookup)self;
 635         } else {
 636             lookup = MethodHandles.publicLookup();
 637         }
 638         return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides, lookup);
 639     }
 640 
 641     /**
 642      * When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java
 643      * adapter), returns an object that can be used to invoke superclass methods on that object. E.g.:
 644      * <pre>
 645      * var cw = new FilterWriterAdapter(sw) {
 646      *     write: function(s, off, len) {
 647      *         s = capitalize(s, off, len)
 648      *         cw_super.write(s, 0, s.length())
 649      *     }
 650      * }
 651      * var cw_super = Java.super(cw)
 652      * </pre>
 653      * @param self the {@code Java} object itself - not used.
 654      * @param adapter the original Java adapter instance for which the super adapter is created.
 655      * @return a super adapter for the original adapter
 656      */
 657     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super")
 658     public static Object _super(final Object self, final Object adapter) {
 659         return Bootstrap.createSuperAdapter(adapter);
 660     }
 661 
 662     /**
 663      * Returns an object that is compatible with Java JSON libraries expectations; namely, that if it itself, or any
 664      * object transitively reachable through it is a JavaScript array, then such objects will be exposed as
 665      * {@link JSObject} that also implements the {@link List} interface for exposing the array elements. An explicit
 666      * API is required as otherwise Nashorn exposes all objects externally as {@link JSObject}s that also implement the
 667      * {@link Map} interface instead. By using this method, arrays will be exposed as {@link List}s and all other
 668      * objects as {@link Map}s.
 669      * @param self not used
 670      * @param obj the object to be exposed in a Java JSON library compatible manner.
 671      * @return a wrapper around the object that will enforce Java JSON library compatible exposure.
 672      */
 673     @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
 674     public static Object asJSONCompatible(final Object self, final Object obj) {
 675         return ScriptObjectMirror.wrapAsJSONCompatible(obj, Context.getGlobal());
 676     }
 677 }