Ad suggested fix for "JDK-8234959 FXMLLoader does not populate ENGINE_SCOPE Bindings with FILENAME and ARGV"

Rony G. Flatscher Rony.Flatscher at wu.ac.at
Tue Feb 18 12:36:26 UTC 2020


[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>




More information about the openjfx-dev mailing list