Hi,
have you considered directly contributing your proposed change via a PR on
<https://github.com/openjdk/jfx>? According to my experience this may speed
up things considerably but don't forget to follow the procedures as
outlined in
<https://github.com/openjdk/jfx/blob/master/CONTRIBUTING.md>.
--Michael
Am 13.11.19 um 15:14 schrieb Rony G. Flatscher:
Hmm, not getting any feedback so far, so wondering if there are currently any
Java developers who
take advantage of the ability of FXMLLoader to have FXML controllers
implemented in any of the Java
javax.script languages?
For those, who use scripting languages for FXML controllers the request that
FXMLLoader adds both
entries, ScriptEngine.FILENAME (for debugging, logging) and ScriptEngine.ARGV
() (for making the
event object available directly as an argument) into the engine Bindings,
should be quite helpful
while developing and running the scripts.
[Personally I am using the scripting engine ooRexx successfully for teaching oo
programming from
scratch to JavaFX in a single semester (four hour lecture, eight ECTS) at a
Business Administration
university. So these two missing features in the current FXMLLoader support for
FXML controllers
would help tremendously, especially in case of coding errors as currently it is
not clear from which
file the script that has an error comes from, making it extremely cumbersome
and time consuming in
JavaFX applications that use multiple and complex FXML files.]
Therefore I would kindly ask interested committers for mentoring the proposed
changes. Enclosed
please find a simpler version of the patch that adds these missing features to
the ENGINE_SCOPE
Bindings in the three locations where ScriptEngine.eval() gets invoked (it ).
To comment this simple patch, maybe I should add a few remarks such that the
context becomes clear:
* invoking a script via ScriptEngine.eval() will always be accompanied with
a ScriptContext that
usually maintains two Bindings (Maps):
o one, GLOBAL_SCOPE Bindings, for global entries (used e.g. for putting
the FXML elements that
have an fx:id attribute defined, such that scripts can get access to
them, independent of a
particular ScriptEngine) which can also be used for sharing values
among different script
invocations,
o one, ENGINE_SCOPE Bindings, usually used for individual invocations.
* while a FXML file gets processed sequentially by the FXMLLoader elements
in the form of
"<fx:script source="someScript.ext" />" will cause invoking the
ScriptEngine.eval(Reader): this
patch fetches the ENGINE_SCOPE Bindings and puts the value
"someScript.ext" with the key
ScriptEngine.FILENAME into it (cf. "@@ -1558,6 +1558,9 @@ public class
FXMLLoader" and "@@
-1582,6 +1585,8 @@ public class FXMLLoader" in the patch),
* if an event handler gets defined (e.g. with the event attribute
"<fx:button ...
onAction="someScript">") the FXMLLoader creates a ScriptEventHandler and stores
"someScript" and
the ScriptEngine for executing that script whenever the event fires.
o When an event fires, the current implementation creates a copy of the
current ENGINE_SCOPE
Bindings from the ScriptEngine's ScriptContext, adds its entries to it
after saving the
entry "event" with the ActionEvent object in it. It then changes the
ScriptEngine's current
ScriptContext such that it now uses the new copy of the Bindings as
its ENGINE_SCOPE
Bindings, runs the script using eval() and then restores the
ScriptContext ENGINE_SCOPE
Bindings.
o The supplied patch (cf. "@@ -1675,30 +1680,28 @@ public class
FXMLLoader") instead will
create a copy of the ENGINE_SCOPE Bindings only once at creation time
(and puts the
appropriate ScriptEngine.FILENAME into it using the name of the FXML
file that defines the
event script attribute) and will reuse that Bindings each time the
handler gets invoked,
after putting the actual "event" object and the respective
ScriptEngine.ARGV entry into it.
Using ScriptEngine.eval(String,Bindings) will use the supplied
Bindings as the ENGINE_SCOPE
Bindings for this invocation only, such that no restore is necessary
upon return.
As only entries get added to the engine Bindings that have not been used by
FXMLLoader this simple
patch should not affect existing scripts. The patch has been tested and works.
Maybe it helps the cause for applying this patch, if I point out that I have
been active in a number
of opensource projects, including Apache's BSF which led to my participation as
an expert in JSR-223
which originally defined the javax.script framework introduced with Java 6
(also authored a complete
ScriptEngine implementation with both, the javax.script.Compilable and the
javax.script.Invocable
interfaces).
So looking for interested committers who would be willing to mentor this patch.
Please advise.
---rony
On 06.11.2019 16:05, Rony G. Flatscher wrote:
Using a script engine (javax.script.ScriptEngine) for implementing a FXML
controller there are two
important information missing in the ScriptContext.ENGINE_SCOPE Bindings
supplied to the script used
to eval() the script code:
* ScriptEngine.FILENAME
o This value denotes the file name from where the script code was
fetched that is being eval()'d.
o When debugging script controllers in a complex JavaFX application it
is mandatory to know
the file name the script code was taken from (as such scripts could be
called/run from
different FXML files). Also, in the case of script runtime errors,
usually the file name is
given by the script engine where the error has occurred to ease
debugging, such that it is
important to really supply the filename.
+ Note: the 'location'-URL in ScriptContext.GLOBAL_SCOPE refers the
FXML file, not to the
file that hosts the script that gets run if using the "<fx:script"
element where the
"source" attribute denotes the name of the script file.
o General solution: supply the appropriate ScriptEngine.FILENAME entry
to the
ScriptContext.ENGINE_SCOPE Bindings.
* ScriptEngine.ARGV
o This value denotes the arguments that get passed to the script from
Java in form of a Java
Array of type Object.
o When defining event handlers in FXML files in script code the script
does not get the
appropriate argument. Rather the script programmer needs to access the
ScriptContext.ENGINE_SCOPE and fetch the entry named "event" from
there. Some script engines
may make the entries in the Bindings implicitly available to the
scripts, however this
cannot be expected by default. However, a ScriptEngine.ARGV entry must
be supplied to the
script by the script engine implementor, such that a script coder gets
the event object
argument in the script language's manner.
o General solution: supply the appropriate ScriptEngine.ARGV Object
array to the
ScriptContext.ENGINE_SCOPE Bindings.
With these two changes not only writing controller scripts would be eased, it
also would
instrumentate ScriptContext.ENGINE_SCOPE Bindings the way it was intended by
JSR-223.
Enclosed please find a tested diff for FXMLLoader.java from the current
OpenJavaFX Master (version
14) that implements both, ScriptEngine.FILENAME entries for all script
invocations and in the case
of a script event handler the appropriate ScriptEngine.ARGV entry gets
supplied, allowing the script
to fetch the event object directly as an argument.
As I have signed the OCA the code (in form of a git diff) can be directly
applied to FXMLLoader.java.
If you need the patch in a different form, then please advise.
---rony