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