Search code examples
javamavenintellij-ideajavafxscenebuilder

JavaFX complex project architecture


I found the Scene Builder GitHub page and noticed that their project consists of two other modules: app and kit. Is there any possibility to build a similar architecture, maybe a little easier? I think I should sort out the work of the modules in this case. I will be grateful for the answer and links to materials on this issue.

The GitHub page

The simplified structure of the project looks like this:

app/
├─ src/
kit/
├─ src/
src/
pom.xml/

I tried to create a project through Intellij IDEA and add two modules, but I don't know how to configure dependencies for them or specify a class with the main method from the app module in the configuration, as the IDE does not allow this to be done.


Solution

  • This guide is for multi-module projects with Maven, you can achieve something similar with other build tools such as Gradle or your IDE, but that is not in scope here. The guide is not comprehensive (the detail is best handled through existing tutorials and documentation, for which there is a lot already on the web).

    As noted by Slaw in comments, defining complex project structure in an IDE via manual setup is not recommended and the use of a build tool (Maven or Gradle) is preferred.

    Using multiple custom Java modules in a JavaFX project

    Info on creating and using java modules for JavaFX custom components:

    Some of the info in that link (the stuff related to SceneBuilder import and usage) may not apply to your case, but a lot of the stuff should be similar.

    The guide linked above keeps the different components as separate projects, rather than sub-modules of a parent project. Adding a parent project is a bit more work and requires you to follow some of the steps outlined in the rest of this answer.

    Java modules and Maven modules are different

    Java modules and Maven modules are completely different things. You must understand that. Maven modules handle the build time modularity of the project and Java modules the runtime modularity.

    You can use one or the other, both, or neither. You can set up projects where you create Maven modules 1:1 with Java modules, but it is not a requirement to do it that way.

    Discussion on Java Modules

    Unlike Maven dependencies, java modules enforce and reduce visibility. This requires you to do extra work to define the visible interfaces to a module. That work is unnecessary if Java modules are not used.

    Java modules can provide benefits in terms of reducing complexity and security surfaces in an application, allowing tool-based dependency analysis (e.g. via the jdeps tool and graphviz) and building custom runtimes for applications using jlink or jpackage.

    A major issue with Java modules is that a lot of important software you might depend on is not fully modularized (does not provide a module-info definition). That greatly reduces the benefit that Java modularity can provide and also increases the complexity in creating and delivering a modularized project that also makes use of non-modular software.

    If the java module definition (module-info.java) does not open or export a package from the module, the code in the module cannot be used outside the module.

    While this is a simple concept (and one of the main purposes of modularity). It is a concept unfamiliar to many Java developers not used to working with a module system because Java traditionally hasn't worked that way - if the code was available somewhere on the classpath, it could be used both via direct API calls and through reflection, but this is simply not the case once the code has been modularized using java modules.

    Discussion on Maven Modules

    The best practice for Maven is to have a single primary artifact (e.g. jar file) created for a project. Sometimes this is a bit restrictive and you might want to output multiple artifacts (e.g. output multiple jar files from a build). In this case, the recommended approach is to create multiple Maven modules and have a parent project that references each of the child modules.

    Each module can then act like its own project and output a primary build artifact (single jar file). Upstream build modules can depend on the artifacts built by other modules and make use of them if necessary.

    Maven module guides to follow

    Required reading:

    The best practice is to provide CI-friendly versions for multi-module projects, though whether to follow that is up to you.

    Advice on modularization

    One consideration you should have is why you are modularizing your project. For the SceneBuilder project you reference, the modularity is there so that tool providers (such as IDE builders) can use the Scene Builder kit module to provide the functionality of Scene Builder embedded in their IDE, rather than as a standalone application (as is provided by the SceneBuilder app module that relies on the kit for its implementation). Your reason for introducing modularity will likely be different, but you should be able to reasonably articulate it to somebody who may ask.

    I would caution against introducing many modules to a project, as it can make the project more difficult to work with. For instance, if you look at the core JavaFX system (which is huge), it consists of seven modules in total, each with a well-defined reason for existence.

    My advice is:

    1. Use maven modules for large complex projects in cases where it makes sense (e.g. a multi-tier app with a module for the front-end UI and a module for the back-end server).
    2. Use Java modules for projects that depend only on modular dependencies (those that include module-info) and probably skip creating Java modules if that is not the case.