JDK-8245873 : FXMLLoader: if script engines implement javax.script.Compilable compile scripts
  • Type: CSR
  • Component: javafx
  • Sub-Component: fxml
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: openjfx15
  • Submitted: 2020-05-26
  • Updated: 2020-06-24
  • Resolved: 2020-06-24
Related Reports
CSR :  
Description
Summary
-------

Have javafx.fxml.FXMLLoader compile FXML scripts before evaluating them, if the script engine
implements the javax.script.Compilable interface to speed up execution. In case compilation
throws a javax.script.ScriptException fall back to evaluating the uncompiled script. Allow
control of script compilation with a "compile" processing instruction (PI) for FXML files.


Problem
-------

javafx.fxml.FXMLLoader is able to execute scripts in Java script languages
(javax.script.ScriptEngine implementations) referred to or embedded in a FXML file.

If a script engine implements the javax.script.Compilable interface, then such scripts could be
compiled and the resulting javax.script.CompiledScript could be executed instead using its
eval() methods.

Evaluating the javax.script.CompiledScript objects may help speed up the execution of script
invocations, especially for scripts defined for event attributes in FXML elements (e.g. like
onMouseMove) which may be repetitively invoked and evaluated.


Solution
-------

Before evaluating the script code test whether the javax.script.ScriptEngine implements
javax.script.Compilable. If so, compile the script to a javax.script.CompiledScript object first
and then use its eval() method to evaluate the script, otherwise continue to use the
javax.script.ScriptEngine's eval() method instead. Should compilation of a script yield
(unexpectedly) a javax.script.ScriptException then fall back to using the
javax.script.ScriptEngine's eval() method. A new processing instruction "compile" allows control of
the compilation of scripts ("true" sets compilation on, "false" to set compilation off) in FXML
files.


Specification
-------

If a javax.script.ScriptEngine implements the javax.script.Compilable interface, then use its
compile() method to compile the script to a javax.script.CompiledScript object and use its
eval() method to run the script. In the case that the compilation throws (unexpectedly) a
javax.script.ScriptException log a warning and fall back to using the
javax.script.ScriptEngine's eval() method instead.
To allow setting this feature off and on while processing the FXML file a "compile" processing
instruction (`"<?compile false?>"` or `"<?compile true?>"`) gets defined that allows to turn
compilation off and on throughout a FXML file.


### Additions to introduction_to_fxml:

_Event Handling section:_

> <p>Note: to turn off automatic compilation of script code place the processing instruction <span class="code">&lt;?compile false?&gt;</span> before the element that contains the script. To turn on compilation of script code again use the processing instruction <span class="code">&lt;?compile true?&gt;</span> (or short: <span class="code">&lt;?compile?&gt;</span>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.</p>

_Scripting section:_

> <p>Scripts are compiled by default, when they are first loaded, if the <span class="code">ScriptEngine</span> implements the <span class="code">javax.script.Compilable</span> interface. If compilation fails, the <span class="code">FXMLLoader</span> will fall back to interpreted mode.</p>
> <p>Note: to turn off automatic compilation of script code place the processing instruction <span class="code">&lt;?compile false?&gt;</span> before the script element. To turn on compilation of script code again use the processing instruction <span class="code">&lt;?compile true?&gt;</span> (or short: <span class="code">&lt;?compile?&gt;</span>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.</p>


### Spec diffs:

javafx/fxml/doc-files/introduction_to_fxml.html

```
@@ -641,6 +641,8 @@ myText = This is the text!
 
 <p>Note the use of the language processing instruction at the beginning of the code snippet. This PI tells the FXML loader which scripting language should be used to execute the event handler. A page language must be specified whenever inline script is used in an FXML document, and can only be specified once per document. However, this does not apply to external scripts, which may be implemented using any number of supported scripting languages. Scripting is discussed in more detail in the next section.</p>
 
+<p>Note: to turn off automatic compilation of script code place the processing instruction <span class="code">&lt;?compile false?&gt;</span> before the element that contains the script. To turn on compilation of script code again use the processing instruction <span class="code">&lt;?compile true?&gt;</span> (or short: <span class="code">&lt;?compile?&gt;</span>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.</p>
+
 <h4><a id="controller_method_event_handlers">Controller Method Event Handlers</a></h4>
 <p>A controller method event handler is a method defined by a document's "controller". A controller is an object that is associated with the deserialized contents of an FXML document and is responsible for coordinating the behaviors of the objects (often user interface elements) defined by the document.</p>
 
@@ -770,7 +772,11 @@ attribute must be used.</p>
 <p>
 The <span class="code">&lt;fx:script&gt;</span> tag allows a caller to import scripting code into or embed script within a FXML file. Any JVM scripting language can be used, including JavaScript, Groovy, and Clojure, among others. Script code is often used to define event handlers directly in markup or in an associated source file, since event handlers can often be written more concisely in more loosely-typed scripting languages than they can in a statically-typed language such as Java.</p>
 
-<p>For example, the following markup defines a function called <span class="code">handleButtonAction()</span> that is called by the action handler attached to the <span class="code">Button</span> element:</p>
+<p>Scripts are compiled by default, when they are first loaded, if the <span class="code">ScriptEngine</span> implements the <span class="code">javax.script.Compilable</span> interface. If compilation fails, the <span class="code">FXMLLoader</span> will fall back to interpreted mode.</p>
+
+<p>Note: to turn off automatic compilation of script code place the processing instruction <span class="code">&lt;?compile false?&gt;</span> before the script element. To turn on compilation of script code again use the processing instruction <span class="code">&lt;?compile true?&gt;</span> (or short: <span class="code">&lt;?compile?&gt;</span>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.</p>
+
+<p>The following example markup defines a function called <span class="code">handleButtonAction()</span> that is called by the action handler attached to the <span class="code">Button</span> element:</p>
 
 <pre class="code">
 &lt;?language javascript?&gt;
@@ -798,6 +804,8 @@ The <span class="code">&lt;fx:script&gt;</span> tag allows a caller to import sc
 
 <div class="caption">example.fxml</div>
 <pre class="code">
+&lt;?language javascript?&gt;
+
 &lt;?import javafx.scene.control.*?&gt;
 &lt;?import javafx.scene.layout.*?&gt;

```

javafx/fxml/FXMLLoader.java

```
+    /**
+     * The tag name of the compile processing instruction.
+     * @since 15
+     */
+    public static final String COMPILE_PROCESSING_INSTRUCTION = "compile";

```
Comments
Moving to Approved.
24-06-2020

1. Summary: "PI" --> "processing instruction (PI)"; Solution & Specification: "process instruction" --> "processing instruction" 2. Fixed
23-06-2020

1) Consistent usage of the text "Processing Instruction" is needed. It is referred to as "PI" in Summary section, while in Solution and Specification Sections, it is referred to as "process instruction" 2) Typo in Compatibility Risk Description: "instructions" --> "instruction"
23-06-2020

Moving to Provisional.
22-06-2020

I am submitting this CSR on behalf of Rony.Flatscher at wu.ac.at who is the author of this proposed change. I am sponsoring it for him.
19-06-2020

Updated with the latest version, plus added the raw diffs for the FXMLLoader class and the "Introduction to FXML" HTML doc.
18-06-2020

NOTE: the above text for the CSR is copied from [GItHub PR #192](https://github.com/openjdk/jfx/pull/192) which is under review. It will need updates to at least the Specification section to include the diffs to the API docs for the FXMLLoader class and the "Introduction to FXML" HTML doc.
26-05-2020