Designing JavaFX Business Applications (Part 2)

This is the second part of my series about JavaFX architecture and best practice for (business) application. You can find the first part about middleware here.

In this post I will show you a simply and modern way to bind your data model to your view by using Context Dependency Injection (CDI).

CDI?? What the hell??

CDI is a modern design pattern that is for example part of JEE. By using dependency injection you can remove hard coded dependencies  in your code. Here is a short example:

public class Controller {

    @Inject
    Model model;

    public void action() {...}
}

If the Controller will be created by a CDI-Container the model field will be injected. This means that the CDI-Container will fill the field with a suitable instance of Model. How this model is created is not part of the Controller class. The controller only knows that he will get a injected instance of Model and can work with it.
This is only a very short introduction to CDI. If you want to use it please read a better documentation :)

How a JavaFX application is mostly designed until now

In a normal business application you will have views and workflows. For example you will have a overview of some important business values and a form dialog with CRUD functions.
Normally you will define your views by code or with the Scene Builder. If you use the Scene Builder you can transfer all your UI code into the fxml file and handle the logic inside a controller class. The controller can now access the business data by calling data stores or any other of your classes.
cdi1
This pattern is good and is working much better that your old Swing code. You have a clean separation between the view and the business logic. But there are still some problems here:

  • The controller has hard dependencies to you business data classes.
  • The controller class is defined inside the fxml file.
  • Providing special business object instances only for one view workflow isn’t easy.

I will try to solve this problems with a new approach of JavaFX client development.

Let’s pimp my JavaFX application

To create a real modern and modular version of this we will do some inversion of control. First of all I don’t like that the controller class for a fxml-view is defined inside the fxml. This is a refactoring killer. Cause if you rename the class or move it to another package this binding is broken. In addition I like it more to define the used view in the controller. Maybe this is not 100% compatible with the MVC pattern where different views can easily share one controller but we can define all dependencies in java code. To inverse this dependency I created a FXMLController annotation:

@FXMLController("/com/guigarage/application/views/MyView.fxml")
public class MyController {
...
}

The internal path to the fxml file is defined by the annotation. By doing so I can simply create a view:

Node myView FXMLHelper.create(MyController.class);

FXMLHelper.create(..) is a Method that I created to do some magic (Don’t be afraid, I will release a code for this design pattern later). The method creates the controller instance and the view and bind them.
We can now easily add the node to our scene graph.
cdi2
But wait! Where is the controller instance? We don’t have access to this object…
Right, cause we don’t need it :) Cause now comes the CDI magic.

Using the CDI pattern in JavaFX

A first project that shows the use of CDI in JavaFX is afterburner.fx by Adam Bien. With this framework you can easily inject objects in your JavaFX controller. But this framework is very lightweight and don’t support all default CDI features. There are no producers, scopes, etc.
I created a new API that is currently based on Weld (the JEE default implementation for CDI) and provides all the default CDI features. By using it you can use the @Inject annotation in you view controllers:

public class MyController {

   @Inject
   Model myModel;
}

The model will be injected to your controller as mentioned above. Other CDI Annotations will work, too. Here is an example of a more complex version of a controller:

public class MyController {

   @Inject
   @ModelQualifier
   Model myModel;

   @PostConstruct
   public void init() {....}
}

public class ModelFactory {

    @Produces
    @ModelQualifier
    public Model getModel() {
        ....
    }
}

In this example the model has a custom Qualifier annotation (@ModelQualifier). This will define a special Model type. This type is created by the ModelFactory. The getModel() method has a @Producer annotation that defines this method as a producer for the model class. Additionally the init() method of the controller has a PostConstruct annotation. This method will automatically called once a controller is created.

Putting it all together

After I added the @FXMLController annotation and CDI to my basic application it is really easy to create new views. The UI can be easily created by using the Scene Builder. Once this is done you can create the controller class and use CDI inside it. Cause you can inject everything that is needed it will be very easy to capsulate a view-controller-union as a single module. To create this I only need a line of code (as mentioned above):

Node myView FXMLCDI.create(MyController.class);

The FXMLCDI util class (my custom one) handles all the FXML and CDI stuff.
cdi3

Thinking about Scopes

Cause CDI is mostly used in JEE context at the moment most of the Scopes don’t fit to a JFX application. But we will need Scopes here, too.
In the default CDI Scope a new instance of a class is created for every injection. Secondly you can use a singleton scope. By doing so only one instance of the class will be used in your application. All other default scopes are related to web applications (RequestScope, SessionScope, …) and won’t fit in a JavaFX application. While looking at other frameworks I found some interesting scopes that are part of ADF. Here you can use a ViewScope and a ViewFlowScope. I think this scopes are very useful for client applications and one of my next steps is the integration of this scopes in my FXML/CDI Framework.

A simple example

Let’s think about a dialog with some very important business values. This values should only be accessed by this dialog. But your application offers a twitter integration to post some stuff. The Twitter configuration is defined globally for the whole application. If you want to add a function to twitter the business values by just clicking a button in your dialog the controller could look like this:

@FXMLController("/com/guigarage/application/views/ImportantDialog.fxml")
public class ImportantDialogController {

   @Inject
   @DialogScope
   Model importantModel;


   @Inject
   @ApplicationScope
   Twitter twitter;

   @PostConstruct
   public void init() {
      importantModel.loadAllImportantValues();   
   }

   @FXML
   public void twitter() {
      twitter.post(importantModel.getImportantBusinessValues());
   }
}

And how can I use this stuff?

At the moment my complete code is experimental but I plan to release it once it is more clean. Maybe you have some cool additional ideas for this pattern of JavaFX application development that I can add to the framework before it will be released ;)

16 Responses to Designing JavaFX Business Applications (Part 2)

  1. I would like to see how you hooked up Scopes for FX, Im a Seam JSF2 developer by day, but have been playing with an FX port of my site and using CDI and scopes in FX will be AWESOME!

  2. Very nice! I would really like to see the actual code even if it’s not clean, just to see how you wired everything up in the annotations etc :-)

  3. I agree, would be nice to take a look at the code early on ;)
    The sooner you can gather feedback the better I believe.

    Thanks anyhow for this wonderful article.

  4. Worked on Application, View & ViewFlow Contexts yesterday. I plan to post a update next week. Don’t know if I will have enough time to release a base API next week…

  5. Hi,

    I like your concept and I was wondering if you would like to extend it to something like this:

    https://www.lucidchart.com/publicSegments/view/51b8507c-21b4-401f-b82d-39680a008629/image.png

    I have to write a JavaFX framework which will let me to customize my application for certain clients. I don’t want to go for a full module system like OSGi because I don’t see the need for larger ecosystem with 3rd party developers around my application. I just need a more classic and easy to maintain layered approach. Would you like to collaborate on something like that ?

      • Lets say you’ve build a business application using your pattern with JavaFX and CDI. It’s ok, nice, some clients use it out-of-the-box. But from time to time other clients want to customize it – make some changes in the GUI and its behavior that would not be welcomed by other clients.

        You could always make a branch in git and change the code directly. But this will be a pain to maintain when you’ll have to do an upgrade to the custom app and merge it with the mainstream release.

        You could also go for a full blown module system like you have in Eclipse or Netbeans. But those systems in most cases only let you add new GUI components easily. There is now easy way for module A to modify the components of module B and their behavior. Besides module systems add a lot of complexity like dependency management, over-encapsulation, dependent jar management and versioning.

        A more simple and old-school approach is adding a customization layer (one per client) over your application in a separate jar, which will use the mainstream jar. You can easily extend controllers and tell CDI to inject your custom ones everywhere instead of the standard ones. But what about extending the GUI described in FXML ? I think the best solution would be to use a XSLT transformation associated with a custom controller to add/change what you need.

  6. Okay, I am very interested in this and would like to echo the call for source code! I am new to java and still learning about all of these technologies, so it is more difficult for me to connect the dots without the source code. I searched through the rest of your blog, which is very nice, but I did not see any followup posts. I would love to learn more about your approach and take a look at the source, no matter how messy!

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>