org.netbeans.libs.graalsdk.package-info Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** Polyglot scripting tutorial.
*
*
* Polyglot Scripting Tutorial
*
*
* This tutorial shows how to embed the various languages in a
* NetBeans or even plain Java application via {@link org.netbeans.api.scripting.Scripting} helper methods. This
* environment lets Java interoperate with standard as well as
* GraalVM based
* guest languages via foreign objects and foreign functions.
* For example Java code
* can directly access guest language methods, objects, classes,
* and some complex data structures
* with Java-typed accessors. In the reverse direction, guest language code can access Java objects,
* classes, and constructors.
*
* This tutorial helps you get started, starting with setup instructions, followed by descriptions of
* different interoperation scenarios with (working) code examples.
*
*
*
Contents
*
*
*
*
* Setup
*
* The most advanced features that this API provides work in cooperation with
* GraalVM.
* Downloading
* GraalVM and running your (NetBeans) application on
* GraalVM will give you access to the
* polyglot features highlighted in this tutorial.
*
* NetBeans modules are
* uploaded to Maven central. You can use them from your pom.xml
* file as:
*
*
<dependency>
<groupId>org.netbeans.api</groupId>
<artifactId>scripting</artifactId>
<version>11</version> <!-- or any later version -->
</dependency>
*
*
* Get started
*
* Guest language "Hello World!"
*
* Integrating scripting into your Java application starts with building
* an instance of {@link javax.script.ScriptEngineManager} via
* {@link org.netbeans.api.scripting.Scripting#createManager()} helper method.
* You can then use the engine to
* {@link javax.script.ScriptEngine#eval evaluate}
* guest language source code.
*
* The following example evaluates a Python source, let it print a message,
* returns it, and then "casts" the result to a Java string.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#testHelloWorld}
*
*
It's a polyglot world
*
* How to list all available languages? To obtain all registered engine
* factories in the system use:
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#listAll}
*
* When the above code snippet is executed on GraalVM it may print:
*
Found Oracle Nashorn
Found Graal.js
Found GraalVM:js
Found GraalVM:llvm
Found GraalVM:python
*
* e.g. a mixture of standard script engines in the JDK with additional ones
* provided as GraalVM languages located
* via dedicated implementation of {@link org.netbeans.spi.scripting.EngineProvider}
* interface
*
* Add a language
*
* GraalVM
* download comes with highly efficient implementations of JavaScript.
* Additional languages like
* Ruby,
* the R and
* Python
* can be installed via the bin/gu
Graal Updater tool:
*
*
* $ /graalvm/bin/gu available
* Downloading: Component catalog
* ComponentId Version Component name
* ----------------------------------------------------------------
* python 1.0.0-rc9 Graal.Python
* R 1.0.0-rc9 FastR
* ruby 1.0.0-rc9 TruffleRuby
* $ /graalvm/bin/gu install python
* Downloading: Component catalog
* Processing component archive: Component python
*
*
* After invoking this command and downloading the bits, the JVM will be
* ready to execute Python scripts.
*
* Hello World in Python and JavaScript
*
* The {@link org.netbeans.libs.graalsdk.Scripting Scripting.createManager()} method
* is your gateway to polyglot world! Just create a manager and it can serve
* as a hub where various language engines connect together. Following example
* shows JavaScript and Python interacting with each other:
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#testHelloWorldInPythonAndJavaScript}
*
* Languages provided by GraalVM use the
* {@link javax.script.ScriptEngineManager} created by
* {@link org.netbeans.libs.graalsdk.Scripting#createManager()} factory
* method as a connection point to talk to each other and mutually share
* and use its objects, functions and other services.
*
*
Cast Array to List
*
* Dynamic languages may represent array in their own special ways.
* However the
* {@link org.netbeans.libs.graalsdk.Scripting} interoperation let's you
* view each array-like object as {@link java.util.List}. Just
* "{@linkplain javax.script.Invocable#getInterface(java.lang.Object, java.lang.Class) cast it}"
* like in following example:
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#testCastJsArray}
*
*
*
Call guest language functions from Java
*
* {@link org.netbeans.libs.graalsdk.Scripting} interoperation lets Java call
* foreign functions that guest language code exports
* (details vary across languages).
* This section presents a few examples.
*
* Define and call a JavaScript function
*
* A function exported from a dynamic language becomes a callable foreign function
* by giving it a Java type, for example the Java interface {@code Multiplier} in the following code.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#callJavaScriptFunctionFromJava}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of two arguments
* represented as {@link java.lang.Object} that can be
* {@linkplain javax.script.Invocable#getInterface(java.lang.Object, java.lang.Class) "cast"}
* to a foreign function with a Java type.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* Define and call a Python function
*
* The same example can be rewritten to Python:
*
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#testPythonFunctionFromJava}
*
* Notes:
*
* - Evaluating the Python source defines a {@code mul} function and also
* returns it as a value to the Java code that can
* {@linkplain javax.script.Invocable#getInterface(Class) "cast"}
* it to a foreign function with a given Java type.
*
*
* Call an existing R function
*
* In this sample we use a reference to existing R function {@code qbinom} from the built-in stats package.
*
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#callRFunctionFromJava}
*
* Don't forget to install support for the R language into your GraalVM
* instance:
*
*
* $ /graalvm/bin/gu install
*
*
* Call multiple guest language functions with shared state from Java
*
* Often it is necessary to export multiple dynamic language functions that work
* together, for example by sharing variables. This can be done by giving
* an exported group of functions a Java type with more than a single method,
* for example the Java interface {@code Counter} in the following code.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#callJavaScriptFunctionsWithSharedStateFromJava}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of no arguments
* assigned to {@code jsFunction}) that can be
* {@linkplain javax.script.Invocable#invokeMethod executed directly},
* without giving it a Java type.
* - Executing {@code jsFunction} returns a JS dynamic object (containing two methods
* and a shared variable)
* that can be {@linkplain javax.script.Invocable#getInterface "cast"}
* to a foreign object with a Java type.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* Access guest language classes from Java
*
* Access a JavaScript class
*
* The ECMAScript 6 specification adds the concept of typeless classes to JavaScript.
* NetBeans {@link org.netbeans.libs.graalsdk.Scripting}
* interoperation allows Java to access fields and functions of a JavaScript class,
* for example the foreign function factory and class given the Java type
* {@code Incrementor} in the following code.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#callJavaScriptClassFactoryFromJava}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of no arguments assigned
* to {@code jsFunction} that can be
* {@linkplain javax.script.Invocable#invokeMethod executed directly},
* without giving it a Java type.
* - Executing {@code jsFunction} returns a JS factory method for class
* {@code JSIncrementor} that can also be executed directly.
* - Executing the JS factory returns a JS object that can
* be {@linkplain javax.script.Invocable#getInterface "cast"}
* to a foreign object with the Java type {@code Incrementor}.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* Access guest language data structures from Java
*
* The method {@link javax.script.Invocable#getInterface invocable.getInterface(Class)}
* plays an essential role supporting interoperation between Java and guest language data
* structures.
* This section presents a few examples.
*
* Access a JavaScript Array
*
* The following example demonstrates type-safe Java foreign access
* to members of a JavaScript array with members of a known type,
* accessed as a Java {@link java.util.List} of objects with type given by interface {@code Point}.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#accessJavaScriptArrayWithTypedElementsFromJava}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of no arguments
* assigned to {@code jsFunction}) that can be
* {@linkplain javax.script.Invocable#getInterface "cast"}
* to a foreign function with Java type {@code PointProvider}.
* - Invoking the foreign function (assigned to {@code pointProvider}) creates
* a JS array, which is returned as a foreign object
* with Java type {@code List
}.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* Access a JavaScript JSON structure
*
* This example demonstrates type-safe Java foreign access to a JavaScript JSON-like
* structure, based on JSON data returned by a GitHub API.
* The GitHub response contains a list of repository objects. Each repository has an id,
* name, list of URLs, and a nested structure describing its owner. Java interfaces
* {@code Repository} and {@code Owner} define the structure as Java types.
*
* The following Java code is able to inspect a JavaScript JSON data structure
* generated by "mock parser" in a type-safe way.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#accessJavaScriptJSONObjectFromJava}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of no arguments assigned
* to {@code jsFunction} that can be
* {@linkplain javax.script.Invocable#invokeMethod executed directly},
* without giving it a Java type.
* - Executing {@code jsFunction} returns a JS mock JSON parser function
* (assigned to {@code jsMockParser}), that can be
* {@linkplain javax.script.Invocable#getInterface "cast"}
* to a foreign function with Java type {@code ParseJSON}.
* - Calling the Java-typed mock parser creates a JS data structure, which is
* returned as a foreign object with Java type {@code List
}.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* View any Object as Map
*
* Each dynamic object coming from a GraalVM
* language can be "cast" to a {@link java.util.Map}. Here is an example:
*
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#testCastPythonObj}
*
* While not type-safe, it is a generic approach able to inspect objects
* of unknown structure.
*
*
Access Java from guest languages
*
* Just like Java can access guest language objects, the guest languages may
* access Java objects, their fields and call their methods. Few examples
* follow.
*
* Access Java fields and methods from JavaScript
*
* Public members of Java objects can be exposed to guest language code
* as foreign objects, for example Java objects of type {@code Moment} in
* the following example.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#accessFieldsOfJavaObject}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of one argument
* assigned to {@code jsFunction} that can be executed directly with one argument.
* - The Java argument {@code javaMoment} is seen by the JS function as a
* foreign object whose public fields are visible.
*
- Executing {@code jsFunction} returns a JS number
* that can be
* {@linkplain javax.script.Invocable#getInterface "cast"}
* to a Java {@link java.lang.Number} and then to a Java {@code int}.
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
* The multiple steps needed to convert the result in the above example
* produces awkward code that can be simplified.
* Instead of invoking the JS function directly, and "casting" the wrapped JS result,
* we can instead
* {@linkplain javax.script.Invocable#getInterface "cast"}
* the JS function to a Java foreign function (of type {@code MomentConverter}) that
* returns the desired Java type directly, as shown in the following variation.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#accessFieldsOfJavaObjectWithConverter}
*
*
Access Java constructors and static methods from JavaScript
*
* Dynamic languages can also access the public constructors and public static methods
* of any Java class for which they are provided a reference.
* The following example shows JavaScript access to the public constructor of a Java
* class.
*
* {@codesnippet org.netbeans.libs.graalsdk.ScriptingTutorial#createJavaScriptFactoryForJavaClass}
*
* Notes:
*
* - Evaluating the JS source returns an anonymous JS function of one argument
* assigned to {@code jsFunction} that can be executed directly with one argument.
* - The Java class argument {@code Moment.class} is seen by the JS function as a
* foreign class whose public constructor is visible.
*
- Executing {@code jsFunction} with the Java class argument returns
* a JS "factory" function (for the Java class) that can be
* {@linkplain javax.script.Invocable#getInterface "cast"}
* to the desired Java function type ({@code MomentFactory}).
* - Parentheses around the JS function definition keep it out of JavaScript's
* global scope, so the Java object holds the only reference to it.
*
*
*
*
*/
package org.netbeans.libs.graalsdk;