alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (NativeJava.java)

This example Java source code file (NativeJava.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

class, classnotfoundexception, context, function, nativearray, nativejava, object, reflection, scriptobject, staticclass, string, stringbuilder, suppresswarnings, undefined, unsupportedoperationexception, util

The NativeJava.java Java example source code

/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.nashorn.internal.objects;

import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ListAdapter;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;

/**
 * This class is the implementation for the {@code Java} global object exposed to programs running under Nashorn. This
 * object acts as the API entry point to Java platform specific functionality, dealing with creating new instances of
 * Java classes, subclassing Java classes, implementing Java interfaces, converting between Java arrays and ECMAScript
 * arrays, and so forth.
 */
@ScriptClass("Java")
public final class NativeJava {

    // initialized by nasgen
    @SuppressWarnings("unused")
    private static PropertyMap $nasgenmap$;

    private NativeJava() {
        // don't create me
        throw new UnsupportedOperationException();
    }

    /**
     * Returns true if the specified object is a Java type object, that is an instance of {@link StaticClass}.
     * @param self not used
     * @param type the object that is checked if it is a type object or not
     * @return tells whether given object is a Java type object or not.
     * @see #type(Object, Object)
     */
    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
    public static Object isType(final Object self, final Object type) {
        return type instanceof StaticClass;
    }

    /**
     * <p>
     * Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects
     * used to represent Java types in Nashorn is not {@link java.lang.Class} but rather {@link StaticClass}. They are
     * the objects that you can use with the {@code new} operator to create new instances of the class as well as to
     * access static members of the class. In Nashorn, {@code Class} objects are just regular Java objects that aren't
     * treated specially. Instead of them, {@link StaticClass} instances - which we sometimes refer to as "Java type
     * objects" are used as constructors with the {@code new} operator, and they expose static fields, properties, and
     * methods. While this might seem confusing at first, it actually closely matches the Java language: you use a
     * different expression (e.g. {@code java.io.File}) as an argument in "new" and to address statics, and it is
     * distinct from the {@code Class} object (e.g. {@code java.io.File.class}). Below we cover in details the
     * properties of the type objects.
     * </p>
     * <p>Constructing Java objects

* Examples: * <pre> * var arrayListType = Java.type("java.util.ArrayList") * var intType = Java.type("int") * var stringArrayType = Java.type("java.lang.String[]") * var int2DArrayType = Java.type("int[][]") * </pre> * Note that the name of the type is always a string for a fully qualified name. You can use any of these types to * create new instances, e.g.: * <pre> * var anArrayList = new Java.type("java.util.ArrayList") * </pre> * or * <pre> * var ArrayList = Java.type("java.util.ArrayList") * var anArrayList = new ArrayList * var anArrayListWithSize = new ArrayList(16) * </pre> * In the special case of inner classes, you can either use the JVM fully qualified name, meaning using {@code $} * sign in the class name, or you can use the dot: * <pre> * var ftype = Java.type("java.awt.geom.Arc2D$Float") * </pre> * and * <pre> * var ftype = Java.type("java.awt.geom.Arc2D.Float") * </pre> * both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name * as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the * dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to * dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads * the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested * inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An * alternative way to access the inner class is as a property of the outer class: * <pre> * var arctype = Java.type("java.awt.geom.Arc2D") * var ftype = arctype.Float * </pre> * <p> * You can access both static and non-static inner classes. If you want to create an instance of a non-static * inner class, remember to pass an instance of its outer class as the first argument to the constructor. * </p> * <p> * If the type is abstract, you can instantiate an anonymous subclass of it using an argument list that is * applicable to any of its public or protected constructors, but inserting a JavaScript object with functions * properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the * JavaScript function will provide implementation for all overloads. E.g.: * </p> * <pre> * var TimerTask = Java.type("java.util.TimerTask") * var task = new TimerTask({ run: function() { print("Hello World!") } }) * </pre> * <p> * Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to * invoking the constructor and passing the argument to it, so you can write the above example also as: * </p> * <pre> * var task = new TimerTask { * run: function() { * print("Hello World!") * } * } * </pre> * <p> * which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract * type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share * the same overloaded name), then instead of an object, you can just pass a function, so the above example can * become even more simplified to: * </p> * <pre> * var task = new TimerTask(function() { print("Hello World!") }) * </pre> * <p> * Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors * that take some arguments, you can invoke those simply by specifying the arguments after the initial * implementation object or function. * </p> * <p>The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, * you can just pass in a function object, and Nashorn will know what you meant: * </p> * <pre> * var timer = new Java.type("java.util.Timer") * timer.schedule(function() { print("Hello World!") }) * </pre> * <p> * Here, {@code Timer.schedule()} expects a {@code TimerTask} as its argument, so Nashorn creates an instance of a * {@code TimerTask} subclass and uses the passed function to implement its only abstract method, {@code run()}. In * this usage though, you can't use non-default constructors; the type must be either an interface, or must have a * protected or public no-arg constructor. * </p> * <p> * You can also subclass non-abstract classes; for that you will need to use the {@link #extend(Object, Object...)} * method. * </p> * <p>Accessing static members

* Examples: * <pre> * var File = Java.type("java.io.File") * var pathSep = File.pathSeparator * var tmpFile1 = File.createTempFile("abcdefg", ".tmp") * var tmpFile2 = File.createTempFile("abcdefg", ".tmp", new File("/tmp")) * </pre> * Actually, you can even assign static methods to variables, so the above example can be rewritten as: * <pre> * var File = Java.type("java.io.File") * var createTempFile = File.createTempFile * var tmpFile1 = createTempFile("abcdefg", ".tmp") * var tmpFile2 = createTempFile("abcdefg", ".tmp", new File("/tmp")) * </pre> * If you need to access the actual {@code java.lang.Class} object for the type, you can use the {@code class} * property on the object representing the type: * <pre> * var File = Java.type("java.io.File") * var someFile = new File("blah") * print(File.class === someFile.getClass()) // prints true * </pre> * Of course, you can also use the {@code getClass()} method or its equivalent {@code class} property on any * instance of the class. Other way round, you can use the synthetic {@code static} property on any * {@code java.lang.Class} object to retrieve its type-representing object: * <pre> * var File = Java.type("java.io.File") * print(File.class.static === File) // prints true * </pre> * <p>{@code instanceof} operator

* The standard ECMAScript {@code instanceof} operator is extended to recognize Java objects and their type objects: * <pre> * var File = Java.type("java.io.File") * var aFile = new File("foo") * print(aFile instanceof File) // prints true * print(aFile instanceof File.class) // prints false - Class objects aren't type objects. * </pre> * @param self not used * @param objTypeName the object whose JS string value represents the type name. You can use names of primitive Java * types to obtain representations of them, and you can use trailing square brackets to represent Java array types. * @return the object representing the named type * @throws ClassNotFoundException if the class is not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object type(final Object self, final Object objTypeName) throws ClassNotFoundException { return type(objTypeName); } private static StaticClass type(final Object objTypeName) throws ClassNotFoundException { return StaticClass.forClass(type(JSType.toString(objTypeName))); } private static Class<?> type(final String typeName) throws ClassNotFoundException { if (typeName.endsWith("[]")) { return arrayType(typeName); } return simpleType(typeName); } /** * Returns name of a java type {@link StaticClass}. * @param self not used * @param type the type whose name is returned * @return name of the given type */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object typeName(final Object self, final Object type) { if (type instanceof StaticClass) { return ((StaticClass)type).getRepresentedClass().getName(); } else if (type instanceof Class) { return ((Class<?>)type).getName(); } else { return UNDEFINED; } } /** * Given a script object and a Java type, converts the script object into the desired Java type. Currently it * performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example: * <pre> * var anArray = [1, "13", false] * var javaIntArray = Java.to(anArray, "int[]") * print(javaIntArray[0]) // prints 1 * print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion * print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion * </pre> * @param self not used * @param obj the script object. Can be null. * @param objType either a {@link #type(Object, Object) type object} or a String describing the type of the Java * object to create. Can not be null. If undefined, a "default" conversion is presumed (allowing the argument to be * omitted). * @return a Java object whose value corresponds to the original script object's value. Specifically, for array * target types, returns a Java array of the same type with contents converted to the array's component type. Does * not recursively convert for multidimensional arrays. For {@link List} or {@link Deque}, returns a live wrapper * around the object, see {@link ListAdapter} for details. Returns null if obj is null. * @throws ClassNotFoundException if the class described by objType is not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object to(final Object self, final Object obj, final Object objType) throws ClassNotFoundException { if (obj == null) { return null; } if (!(obj instanceof ScriptObject) && !(obj instanceof JSObject)) { throw typeError("not.an.object", ScriptRuntime.safeToString(obj)); } final Class<?> targetClass; if(objType == UNDEFINED) { targetClass = Object[].class; } else { final StaticClass targetType; if(objType instanceof StaticClass) { targetType = (StaticClass)objType; } else { targetType = type(objType); } targetClass = targetType.getRepresentedClass(); } if(targetClass.isArray()) { return JSType.toJavaArray(obj, targetClass.getComponentType()); } if(targetClass == List.class || targetClass == Deque.class) { return ListAdapter.create(obj); } throw typeError("unsupported.java.to.type", targetClass.getName()); } /** * Given a Java array or {@link Collection}, returns a JavaScript array with a shallow copy of its contents. Note * that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you * need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will * want to use this method. Example: * <pre> * var File = Java.type("java.io.File") * var listHomeDir = new File("~").listFiles() * var jsListHome = Java.from(listHomeDir) * var jpegModifiedDates = jsListHome * .filter(function(val) { return val.getName().endsWith(".jpg") }) * .map(function(val) { return val.lastModified() }) * </pre> * @param self not used * @param objArray the java array or collection. Can be null. * @return a JavaScript array with the copy of Java array's or collection's contents. Returns null if objArray is * null. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object from(final Object self, final Object objArray) { if (objArray == null) { return null; } else if (objArray instanceof Collection) { return new NativeArray(((Collection<?>)objArray).toArray()); } else if (objArray instanceof Object[]) { return new NativeArray(((Object[])objArray).clone()); } else if (objArray instanceof int[]) { return new NativeArray(((int[])objArray).clone()); } else if (objArray instanceof double[]) { return new NativeArray(((double[])objArray).clone()); } else if (objArray instanceof long[]) { return new NativeArray(((long[])objArray).clone()); } else if (objArray instanceof byte[]) { return new NativeArray(copyArray((byte[])objArray)); } else if (objArray instanceof short[]) { return new NativeArray(copyArray((short[])objArray)); } else if (objArray instanceof char[]) { return new NativeArray(copyArray((char[])objArray)); } else if (objArray instanceof float[]) { return new NativeArray(copyArray((float[])objArray)); } else if (objArray instanceof boolean[]) { return new NativeArray(copyArray((boolean[])objArray)); } throw typeError("cant.convert.to.javascript.array", objArray.getClass().getName()); } private static int[] copyArray(final byte[] in) { final int[] out = new int[in.length]; for(int i = 0; i < in.length; ++i) { out[i] = in[i]; } return out; } private static int[] copyArray(final short[] in) { final int[] out = new int[in.length]; for(int i = 0; i < in.length; ++i) { out[i] = in[i]; } return out; } private static int[] copyArray(final char[] in) { final int[] out = new int[in.length]; for(int i = 0; i < in.length; ++i) { out[i] = in[i]; } return out; } private static double[] copyArray(final float[] in) { final double[] out = new double[in.length]; for(int i = 0; i < in.length; ++i) { out[i] = in[i]; } return out; } private static Object[] copyArray(final boolean[] in) { final Object[] out = new Object[in.length]; for(int i = 0; i < in.length; ++i) { out[i] = in[i]; } return out; } private static Class<?> simpleType(final String typeName) throws ClassNotFoundException { final Class<?> primClass = TypeUtilities.getPrimitiveTypeByName(typeName); if(primClass != null) { return primClass; } final Context ctx = Global.getThisContext(); try { return ctx.findClass(typeName); } catch(ClassNotFoundException e) { // The logic below compensates for a frequent user error - when people use dot notation to separate inner // class names, i.e. "java.lang.Character.UnicodeBlock" vs."java.lang.Character$UnicodeBlock". The logic // below will try alternative class names, replacing dots at the end of the name with dollar signs. final StringBuilder nextName = new StringBuilder(typeName); int lastDot = nextName.length(); for(;;) { lastDot = nextName.lastIndexOf(".", lastDot - 1); if(lastDot == -1) { // Exhausted the search space, class not found - rethrow the original exception. throw e; } nextName.setCharAt(lastDot, '$'); try { return ctx.findClass(nextName.toString()); } catch(ClassNotFoundException cnfe) { // Intentionally ignored, so the loop retries with the next name } } } } private static Class<?> arrayType(final String typeName) throws ClassNotFoundException { return Array.newInstance(type(typeName.substring(0, typeName.length() - 2)), 0).getClass(); } /** * Returns a type object for a subclass of the specified Java class (or implementation of the specified interface) * that acts as a script-to-Java adapter for it. See {@link #type(Object, Object)} for a discussion of type objects, * and see {@link JavaAdapterFactory} for details on script-to-Java adapters. Note that you can also implement * interfaces and subclass abstract classes using {@code new} operator on a type object for an interface or abstract * class. However, to extend a non-abstract class, you will have to use this method. Example: * <pre> * var ArrayList = Java.type("java.util.ArrayList") * var ArrayListExtender = Java.extend(ArrayList) * var printSizeInvokedArrayList = new ArrayListExtender() { * size: function() { print("size invoked!"); } * } * var printAddInvokedArrayList = new ArrayListExtender() { * add: function(x, y) { * if(typeof(y) === "undefined") { * print("add(e) invoked!"); * } else { * print("add(i, e) invoked!"); * } * } * </pre> * We can see several important concepts in the above example: * <ul> * <li>Every specified list of Java types will have one extender subclass in Nashorn per caller protection domain - * repeated invocations of {@code extend} for the same list of types for scripts same protection domain will yield * the same extender type. It's a generic adapter that delegates to whatever JavaScript functions its implementation * object has on a per-instance basis.</li> * <li>If the Java method is overloaded (as in the above example {@code List.add()}), then your JavaScript adapter * must be prepared to deal with all overloads.</li> * <li>To invoke super methods from adapters, call them on the adapter instance prefixing them with {@code super$}, * or use the special {@link #_super(Object, Object) super-adapter}.</li> * <li>It is also possible to specify an ordinary JavaScript object as the last argument to {@code extend}. In that * case, it is treated as a class-level override. {@code extend} will return an extender class where all instances * will have the methods implemented by functions on that object, just as if that object were passed as the last * argument to their constructor. Example: * <pre> * var Runnable = Java.type("java.lang.Runnable") * var R1 = Java.extend(Runnable, { * run: function() { * print("R1.run() invoked!") * } * }) * var r1 = new R1 * var t = new java.lang.Thread(r1) * t.start() * t.join() * </pre> * As you can see, you don't have to pass any object when you create a new instance of {@code R1} as its * {@code run()} function was defined already when extending the class. If you also want to add instance-level * overrides on these objects, you will have to repeatedly use {@code extend()} to subclass the class-level adapter. * For such adapters, the order of precedence is instance-level method, class-level method, superclass method, or * {@code UnsupportedOperationException} if the superclass method is abstract. If we continue our previous example: * <pre> * var R2 = Java.extend(R1); * var r2 = new R2(function() { print("r2.run() invoked!") }) * r2.run() * </pre> * We'll see it'll print {@code "r2.run() invoked!"}, thus overriding on instance-level the class-level behavior. * Note that you must use {@code Java.extend} to explicitly create an instance-override adapter class from a * class-override adapter class, as the class-override adapter class is no longer abstract. * </li> * </ul> * @param self not used * @param types the original types. The caller must pass at least one Java type object of class {@link StaticClass} * representing either a public interface or a non-final public class with at least one public or protected * constructor. If more than one type is specified, at most one can be a class and the rest have to be interfaces. * Invoking the method twice with exactly the same types in the same order - in absence of class-level overrides - * will return the same adapter class, any reordering of types or even addition or removal of redundant types (i.e. * interfaces that other types in the list already implement/extend, or {@code java.lang.Object} in a list of types * consisting purely of interfaces) will result in a different adapter class, even though those adapter classes are * functionally identical; we deliberately don't want to incur the additional processing cost of canonicalizing type * lists. As a special case, the last argument can be a {@code ScriptObject} instead of a type. In this case, a * separate adapter class is generated - new one for each invocation - that will use the passed script object as its * implementation for all instances. Instances of such adapter classes can then be created without passing another * script object in the constructor, as the class has a class-level behavior defined by the script object. However, * you can still pass a script object (or if it's a SAM type, a function) to the constructor to provide further * instance-level overrides. * * @return a new {@link StaticClass} that represents the adapter for the original types. */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object extend(final Object self, final Object... types) { if(types == null || types.length == 0) { throw typeError("extend.expects.at.least.one.argument"); } final int l = types.length; final int typesLen; final ScriptObject classOverrides; if(types[l - 1] instanceof ScriptObject) { classOverrides = (ScriptObject)types[l - 1]; typesLen = l - 1; if(typesLen == 0) { throw typeError("extend.expects.at.least.one.type.argument"); } } else { classOverrides = null; typesLen = l; } final Class<?>[] stypes = new Class[typesLen]; try { for(int i = 0; i < typesLen; ++i) { stypes[i] = ((StaticClass)types[i]).getRepresentedClass(); } } catch(final ClassCastException e) { throw typeError("extend.expects.java.types"); } // Note that while the public API documentation claims self is not used, we actually use it. // ScriptFunction.findCallMethod will bind the lookup object into it, and we can then use that lookup when // requesting the adapter class. Note that if Java.extend is invoked with no lookup object, it'll pass the // public lookup which'll result in generation of a no-permissions adapter. A typical situation this can happen // is when the extend function is bound. final MethodHandles.Lookup lookup; if(self instanceof MethodHandles.Lookup) { lookup = (MethodHandles.Lookup)self; } else { lookup = MethodHandles.publicLookup(); } return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides, lookup); } /** * When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java * adapter), returns an object that can be used to invoke superclass methods on that object. E.g.: * <pre> * var cw = new FilterWriterAdapter(sw) { * write: function(s, off, len) { * s = capitalize(s, off, len) * cw_super.write(s, 0, s.length()) * } * } * var cw_super = Java.super(cw) * </pre> * @param self the {@code Java} object itself - not used. * @param adapter the original Java adapter instance for which the super adapter is created. * @return a super adapter for the original adapter */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super") public static Object _super(final Object self, final Object adapter) { return Bootstrap.createSuperAdapter(adapter); } }

Other Java examples (source code examples)

Here is a short list of links related to this Java NativeJava.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.