Oracle Blog

JavaScript for the JVM.

Saturday Apr 06, 2013

I find myself facing a dilemma today. How should I use Java FX from Nashorn? So far, I have two approaches I could use, but each comes with some issues. Some background first.

Java FX, even though ships with the JDK, is on a different build cycle and has dependencies on elements of the JDK. This arraignment limits Nashorn, which is part of the JDK, from actually having dependencies into Java FX. But, there is a dependency requirement to implement a Java FX application. Java FX applications begin with a subclass instance of javafx.application.Application. Therefore, whatever choice is made, it has to be independent of the JDK (at some point should be part of Java FX.)

The first approach, in general terms, is the easiest to use. It involves using a predefined shell that is similar to jjs but handles the overrides of Application methods init, start and finish. The source of this shell is currently checked into the Nashorn repo under nashorn/tools/fxshell.

To built it you can (cd make ; ant build-fxshell) from within the nashorn repo. The result is in nashorn/dist/nashornfx.jar. To use just java -cp dist/nashornfx.jar jdk.nashorn.tools.FXShell <myscript.js> … . For the JDK savvy you can create a launcher by modelling an entry in jdk/makefiles/CompileLaunchers.gmk after the jjs entry.

The big plus for this approach is that it handles almost everything for you. You just have to define a start method with a few class declarations and that is it. The down side is that ideally you would want this implemented as a jjsfx launcher embedded in the JDK. But then we run into the chicken and egg dependency on Java FX.

The second approach only relies on jjs. With a recent modification to Java.extend (currently only in the nashorn forest), it is now possible to subclass javafx.application.Application. and thus launch from within a script. This sounds like all pluses except for the fact you have to wrap your brain around the fact that FX applications take control of execution and has static init dependencies that require careful use in your program.

I prototyped a simple fxinit.js include that shows how we could implement such a scheme. Ignore the implementation quirks. It's simpler than it seems.

Note the placement of the load("fxinit.js");. Since this is where the FX Application takes control, anything after the load will not complete until the application exits.

One other quirk. Since you can not static init some of Java FX classes until after the application launches. You can not globally (script level) declare any uses of these classes. Uses can be embedded in methods used after the launch, but no where else. This is a style cramp for me.

There is a third approach I have been considering. It involves some argument trickery, but may play out as a better way of doing things. Imagine jjs fxinit.js -- myscript.js -- my scripts args . The -- indicates the beginning of arguments passed to the script. The notion here is that fxinit.js launches the application and then evals myscript.js. This cleanses my script of any quirks, while putting the onus on getting the command line right.