Using JavaFX objects in Java code

As shown in the last article, passing parameters between a JavaFX script and Java code is fairly simple, if the parameters are native to the Java language. But if we want to pass a JavaFX-object, things are different. The main obstacle is the fact, that the Java compiler is not able to read JavaFX scripts directly to extract the needed information. But JavaFX objects can be shared between a JavaFX and Java code by using one of these approaches:

  1. Java interfaces
  2. JSR 223 – Scripting for the Java Platform
  3. com.sun.tools.javafx.ui.FXBean
  4. Using the Java classes created by the JavaFX compiler directly
  5. (JavaFX Reflection)

The last two approaches are mentioned just for completeness. It requires some detailed knowledge of how a JavaFX class is translated into Java code to use the classes directly and it is more cumbersome than the other approaches. For these reasons I’ll skip it in this article, but plan to dedicate an entire article on an overview of how JavaFX classes get translated to Java code. JavaFX Reflection is not implemented yet, but planned. I will add a description for this approach as soon as the details are decided.

Code sample 1 shows a class, which needs to be passed to Java. It has a public function printProperty, which we want to call from Java code.

import java.lang.System;

public class MyJavaFXClass {
    public attribute property: String;
    public function printProperty() {
        System.out.println(property);
    }
}

Code Sample 1: Definition of MyJavaFXClass

Java interfaces

The first approach (and my favorite one) is to use Java interfaces for passing JavaFX classes to Java code. This approach requires to define a Java interface, let the JavaFX-class implement the interface and reference the interface in the Java code. For our little example, we define the interface Printable which is shown in Code Sample 2.

public interface Printable {
    void printProperty();
}

Code Sample 2: The interface Printable

Now we can write a Java class, which takes an implementation of the interface Printable and calls its method printProperty (code sample 3).

public class MyLibraryByInterface {
    public static void print (Printable p) {
        p.printProperty();
    }
}

Code Sample 3: Using an interface to access JavaFX code

The last step is to modify the JavaFX class from code sample 1, so it implements the interface Printable. Also I added some code to create an instance of this class and pass it to the Java library.

import java.lang.System;

public class MyJavaFXClass extends Printable {
    public attribute property: String;
    public function printProperty() {
        System.out.println(property);
    }
}

var o = MyJavaFXClass {
    property: "Hello JavaFX by Interface"
};

MyLibraryByInterface.print(o);

Code Sample 4: Implementing a Java interface with JavaFX Script

This approach has some major advantages. As you can see, the Java code contains no JavaFX-specific code at all. The very same code could handle a Java-object which implements the interface Printable. As a side effect, you can easily write Java-code which can be used with JavaFX-code and Java-code at the same time. Or if you want to migrate parts of an existing Java-application, you can simply switch to use interfaces and then exchange class after class. (Well, it’s probably not going to be THAT simple, but you get the idea.) 🙂
The drawback of this approach is, that one cannot instantiate objects directly as usual when using interfaces. You either need to pass the objects to the Java code or use factory-methods. But the very first factory still needs to be passed to the Java code – or created with the next approach.

JSR 223 – Scripting for the Java Platform

JSR 223 – Scripting for the Java Platform defines mechanisms to access scripting languages from Java code. An implementation for JavaFX Script is available and part of the JavaFX Runtime. With the provided scripting engine, you can read JavaFX-files, compile, and run them. And because the engine for JavaFX Script implements the interface Invocable, it is even possible to call members of JavaFX objects.

In code sample 5, a class is defined, which takes an arbitrary object and tries to call its method printProperty with the help of the JavaFX Scripting Engine. The first two lines of the method get the ScriptingEngineManager, which manages the available scripting engines. The engine for JavaFX Script is requested and casted to the interface Invocable. The line in the try-block invokes the function printproperty of the object that was given as parameter.

import javax.script.*;

public class MyLibraryByScriptEngine {
    public static void print (Object o) {
        ScriptEngineManager manager = new ScriptEngineManager();
        Invocable fxEngine = (Invocable) manager.getEngineByName("javafx");
        try {
            fxEngine.invokeMethod(o, "printProperty");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Code sample 5: Using the JavaFX Script engine

For this approach we do not need to change the JavaFX class at all. The following two lines will create the object and pass it to the Java library.

import MyJavaFXClass;

var o = MyJavaFXClass {
    property: "Hello JavaFX by ScriptEngine"
};

MyLibraryByScriptEngine.print(o);

Code Sample 6: Calling MyLibraryByScriptEngine

As you can see, the Java code to handle a JavaFX object is slighty more complicated than in the first approach. The major drawback is, that the compiler is not able to check the code. Instead you will receive a runtime exception if for example you have a typing error in the method-name printProperty, like I did. 😉

But on the other hand this approach is the most powerful one of these three aproaches, as you are able to access JavaFX-files directly. We have just scratched the possibilities here; if you want to read more, I recommend this general introduction or this article specific to JavaFX Script.

com.sun.tools.javafx.ui.FXBean

The last approach, to use the class FXBean within the JavaFX Runtime, differs from the other approaches, because it does not give you access to the functions of a JavaFX object but to its attributes. The code sample 7 receives an arbitrary object, reads its attribute property with the help of the class FXBean, and prints the attribute.

First an FXBean is constructed using the class of the given object as parameter. The next line requests an attribute with the name property and the type string. Actually the FXBean does not return a String immeadiately, but an ObjectVariable<String>. This is the internal representation of a String-attribute mapped to Java code. We get the value of the attribute by calling the method get, which is printed in the last line of the try-block.

import com.sun.tools.javafx.ui.FXBean;
import com.sun.javafx.runtime.location.ObjectVariable;

public class MyLibraryByFXBean {
    public static void print (Object o) {
        try {
            FXBean bean = new FXBean(o.getClass());
            ObjectVariable<String> attribute =
                    (ObjectVariable<String>)bean.getObject(o, "property");
            String property = attribute.get();
            System.out.println(property);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Code Sample 7: Using the class FXBean

The next two lines of JavaFX code create an object and pass it to the Java library.

import MyJavaFXClass;

var o = MyJavaFXClass {
    property: "Hello JavaFX by FXBean"
};

MyLibraryByFXBean.print(o);

Code Sample 8: Calling MyLibraryByFXBean

As already mentioned above does this approach differ from the others and can therefore not be compared. Using the FXBean you are able to read and modify attributes directly. There are a number of methods to simplify acces to attributes of type Number, Integer, Boolean, and sequences.

After considering the primitive datatypes and Java objects in the last article, we took a look at JavaFX objects in this article. The next article will focus on dealing with sequences in Java code.

16 responses to “Using JavaFX objects in Java code”

  1. leonardoavs Avatar
    leonardoavs

    Sun debería poner más esfuerzo en hacer que los lenguajes fueran más compatibles leyendo java como si java pudiera leer estos lenguajes porque lo que ahora tenemos es muchos lenguajes compatibles con java pero java no es compatible con ellos lo que provoca que no se puedan utilizar construcciones hechas en estos lenguajes desde Java y se pierda el poder de estos lenguajes al no tener una buena integración con Java. Un lenguaje para todos y todos para uno. (Se necesita que se estandarice como son las construcciones (clousure, property, method) de los lenguajes a nivel de bytecode para poder hacer así una verdadera integración entre todos y que todos se puedan comunicar entre ellos sin necesidad de una interface que en fin es un esfuerzo más que no veo por qué haya que hacerlo).

  2. Michael Heinrichs Avatar
    Michael Heinrichs

    @leonardoavs:
    Your comment sounds interesting, but unfortunately my knowledge of foreign languages is very limited. 🙁
    If you could please translate it to English (or German if you prefer), I’d be happy to post a reply.

  3. Jan Erik Paulsen Avatar

    http://translate.google.com/translate_t?langpair=es|en

    He does not want to write wrapper code.

    — Google Translate —
    "Sun should put more effort into making them more compatible languages as if reading java java could read these languages because what we now have is many languages compatible with Java, but Java is not compatible with them causing them to not be possible to use buildings made in these languages from Java to lose the power of these languages by not having a good integration with Java. A language for all and all for one. (Requires that standardize such as construction (clousure, property, method) of the language bytecode level to enable a real integration between all and that everyone can communicate between themselves without having an interface that is in order an effort that most do not see why that has to)."

  4. Michael Heinrichs Avatar
    Michael Heinrichs

    @leonardoavs:
    I have good news for you. JavaFX Script is compiled into regular Java bytecode and therefore it is possible to use it directly. But it requires some knowledge of how features like multiple inheritance, binding of attributes and functions etc. work and so far I do not see the real benefit compared to using interfaces.

    As said before, I will cover this approach in a later article, probably as soon as bound functions are fully implemented. So just be patient. 😉

  5. Leonardoavs Avatar
    Leonardoavs

    Yeah JavaFX Scripts is compiled to ByteCode, but it is not a real integration because Java need to do one Interface to communicate to JavaFX. Apologies for the bad Ingles.

  6. ragaven Avatar
    ragaven

    very worst

  7. Max P. Avatar
    Max P.

    Hello Mike,
    first of all thanks for your good work.
    I am new in Using JavaFX and I am trying to program you example. I am using the Eclipse plug-in for programming ( I think it should be not the Problem ). I stack at the point I want to compile the MyJavaFXClass ( which is a .fx class). The Eclipse compiler do not like that

    printProperty() {
    „ .

    In further examples it was used something like :

    function AnimationExample.composeNode() =

    Group {
    content:
    [Rect {


    It would be really nice if you can give me a hind that I can continue with learning JavaFX
    Thanks allot
    Max P.

  8. cornel Avatar
    cornel

    whre is com.sun.tools.javafx.ui.* package
    please send me this package on mail : tremuricic@yahoo.com.
    i did not find this package

    good day.

  9. cornel Avatar
    cornel

    good day.

    i want to make a javafx browser usse FXBean. this browser is a javafx acpication configurable with xml file. Xml file is send by webservice. i want do develop a special xml file for fxbrowser. this aplication is very good ria aplication. The xml file configure javafxBrowser like Xml configure XULRunner gre.

    the browser will have code java and code java call JavaFX Runtime.
    i need mor information about java fx Runtime.

    my emal addres is tremuricic@yahoo.com
    please send me com.sun.tools.javafx.ui.* package
    good day.

  10. rtkrvj Avatar
    rtkrvj

    Hi!

    Nice article..
    I was just wondering that a small project folders can be provided for the three approaches.
    Specially the second one which uses the script engine.

    Thanks and waiting for the updates.

  11. rtkrvj Avatar
    rtkrvj

    i am talking about the Netbeans Projects.

  12. rtkrvj Avatar
    rtkrvj

    Well i ll be providing it soon on my blog:

  13. Rafik Kocharians Avatar
    Rafik Kocharians

    Hi Mike,
    That is a good example. However, I would like to know if I can call a javafx script which does some plotting say from existing java code? If so, how ?
    many thanks
    Rafik

  14. jx_noob Avatar
    jx_noob

    i try the example 3: JSR 223 – Scripting for the Java Platform

    but when i would run the project, eclipse run it as a javafx application and show errors. but i would to run it as a java application. can you help me? what is with the follow script:

    import MyJavaFXClass;

    var o = MyJavaFXClass {property: "Hello JavaFX by ScriptEngine"};
    MyLibraryByScriptEngine.print(o);

    in which file comes this code?

  15. Superstring Avatar
    Superstring

    Are these ways of using JavaFX from Java still the best options? We are at JavaFX 1.3 without any official way of doing this forth coming from the JavaFX team.

    For my app which is modeled as data and driven by data as opposed to graphic nodes I am thinking about using Java2D and JXLayer with layered jPanels for the visualization of the data. Still, I sure would like to use JavaFX widgets composed with nodes in the jPanels.

    Is it possible to update your article with an included IDE project that demonstrates how to do this. Thanks in advance.

  16. shiv Avatar
    shiv

    hi,
    i got an error importing import com.sun.javafx.runtime.location.ObjectVariable;
    The error says:”cannot access com.sun.javafx.runtime.location.ObjectVariable
    class file for com.sun.javafx.runtime.location.ObjectVariable not found
    mediaSource: metaData.url”.
    please help with this.