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