[1] reports a bug related to FXMLLoader for FXML controllers being implemented
in any one of the
javax.script languages: the invoked scripts are not supplied the standardized
entries
"javax.script.filename" (a string denoting the filename that hosts the script)
and
"javax.script.argv" (an Object[] of positional arguments in the case of event
scripts) in their
engine scope Bindings.
The FXML file below demonstrates how scripts can be defined (using some
hypothetical Java script
language named "rpsl"). In the case of a runtime error (or for debugging
purposes) the script
engines therefore cannot supply the filename that hosts the script that caused
a runtime error (or
which gets currently debugged).
I have prepared a fix for [1], but would like to communicate what it does and
its reasonings first
(making it easy for script programmers to locate erroneous scripts and to fetch
the event argument
as a script argument in event scripts).
---
To illustrate the problem at hand the file "demo_01.fxml" below has been
created, which among other
things defines:
* line # 6: process instruction defines some Java script language named
"rpsl" to be used for
executing the scripts of the fxml file
* line # 11: defines an empty "fx:script" element, denoting in its "source"
attribute the external
script file named "demo_01_topscript.rpsl" (note: the Button element with
the fx:id "idButton"
is not yet defined at that point in time)
* line # 15: defines a Button element with the fx:id "idButton"
* line # 17: defines a script (PCDATA) for the "onMouseClicked" event
attribute for the Button
element (fx:id "idButton")
* line # 18 : defines a script (PCDATA) for the "onButton" event attribute
for the Button element
(fx:id "idButton")
* line # 21: defines an empty "fx:script" element, denoting in its "source"
attribute the external
script file named "demo_01_middlescript.rpsl"
* line # 27: defines an empty "fx:script" element, denoting in its "source"
attribute the external
script file named "demo_01_bottomscript.rpsl"
* line # 29: defines an "fx:script" element with contained PCDATA script
code (note: ends in line
# 32)
* line # 32: defines an "fx:script" element with contained CDATA script code
Currently,
* whatever script gets run (lines # 11, #17, #18, #21, #27, #29, #32), the
name of the file
hosting the script is unknown, because of the missing entry
"javax.script.filename" in the
engine scope Bindings,
* the event scripts (lines # 17, #18) cannot fetch the "event" argument as an
argument, because of
the missing entry "javax.script.argv"
The proposed fix does the following:
* scripts stored in external files (lines #11, #21, # 27): the value of the
"source" attribute
gets stored with the key "javax.script.filename" in the engine scope
Bindings, yielding e.g.:
o line # 11: ...path-to..."demo_01_topscript.rpsl"
o line # 21: ...path-to..."demo_01_middlescript.rpsl"
o line #27: ...path-to..."demo_01_bottomscript.rpsl"
* scripts contained in "fx:script" elements (lines #29, # 32): the FXML
location path is used as
the hosting filename with the string "-script_starting_at_line_#" appended
and stored with the
key "javax.script.filename" in the engine scope Bindings, yielding e.g.:
o line # 29: ...path-to... "demo_01.fxml-script_starting_at_line_29"
o line # 32: ...path-to... "demo_01.fxml-script_starting_at_line_32"
o notes:
+ the dash ('-') following the FXML filename is meant to make
spotting/parsing easier
+ the appended text should be self-describing, allowing the
programmer to immediately spot
the position of the script in question
* event scripts (lines #17, #18):
o the single "event" argument is stored in the local scope Bindings, and
now in addition gets
supplied as the single argument in the single-element Object array
stored with
"javax.script.argv" in the engine scope Bindings
o the FXML location path is used as the hosting filename with the string
"-${eventAttributeName}_attribute_in_element_ending_at_line_#" and
stored with the key
"javax.script.filename" in the engine scope Bindings, yielding e.g.:
+ line #17: ...path-to...
"demo_01.fxml-onAction_attribute_in_element_ending_at_line_19"
+ line #19: ...path-to...
"demo_01.fxml-onMouseClicked_attribute_in_element_ending_at_line_19"
o notes:
+ the dash ('-') following the FXML filename is meant to make
spotting/parsing easier
+ the appended text should be self-describing, allowing the
programmer to closely spot the
position of the event script in question
+ using a minimal edit approach, it is not possible for the suggested
fix to fetch the
starting line (and column) number of the element for which the
event attributes get
processed (nor the exact position of the event attributes for that
matter) in FXMLLoader
therefore hinting the programmer at
"_xxx_attribute_in_element_ending_at_line_#". This
is regarded to be sufficient and will allow the programmer to
immediately locate the
position in the FXML file of the script that may have caused a
runtime exception.
"demo_01.fxml":
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<!-- line # 6 --> <?language rpsl?>
<AnchorPane fx:id="idRoot" prefHeight="240.0" prefWidth="480.0"
xmlns:fx="http://javafx.com/fxml/1">
<!-- line # 11 --> <fx:script source="demo_01_topscript.rpsl" />
<children>
<!-- line # 15 --> <Button fx:id="idButton" text="Press me!"
layoutX="210.0" layoutY="137.0"
onMouseClicked="demo_01.fxml
embedded event -
MouseClicked - line # 17 (PCDATA)"
onAction="demo_01.fxml embedded event - ActionEvent
- line # 18 - LF
entity (&#10;) forces linebreak in attribute value:
(this is on a new line) these characters in attribute values need to be
escaped: <, >,
&, these if used as delimiters: ", ' (PCDATA)" />
<!-- line # 21 --> <fx:script
source="demo_01_middlescript.rpsl" />
</children>
<!-- line # 25 --> <fx:script>demo_01.fxml embedded script rpsl -
line # 25</fx:script>
<!-- line # 27 --> <fx:script source="demo_01_bottomscript.rpsl" />
<!-- line # 29 --> <fx:script>something (line # 29)(PCDATA)
in a=&b (line # 30)
the b>1 (line # 31)
news c<2 (line # 32) </fx:script>
<fx:script><![CDATA[demo_01.fxml (line # 32):
CDATA-section ("<![CDATA[") allows any characters including <, > and &
!! (no need to escape
(line # 33)
these special characters; it is plain CDATA which does not get
processed, just passed on
(line # 34)
including LF etc.
(line # 35)
in a=&b (line # 36)
the b>1 (line # 37)
news c<2 (line # 38)
Watch out that in the code there is no string that exactly matches the
end tag
(line # 39)
for a CDATA-section
(close-square-bracket+close-square-bracket+greater-character
(line # 40) ]]></fx:script>
</AnchorPane>
Any comments, questions, suggestions?
---rony
[1] "JDK-8234959 FXMLLoader does not populate ENGINE_SCOPE Bindings with
FILENAME and ARGV":
<https://bugs.openjdk.java.net/browse/JI-9062887>