Open aalmiray opened 3 years ago
It's worth mentioning that marking the module as open
did not make a difference.
Hi there,
I've been playing with JavaFX and layryy and I think I know what's wrong. It looks the problem appears only when FXML files are used. From this perspective, it might not be an issue of layrry, it is more about internals and default behaviours of JavaFX classes.
When JavaFX loads FXML files it constructs UI controls like VBox, Labels, Buttons etc. Everything that is within an FXML file. The FXMLLoader class, under the hood, resolves a ClaasLoader that will be used for constructing these UI elements BUT, it turns out, that it is a different ClaasLoader that has loaded the application itself (the main class). By default, FXMLLoader takes a classLoader from the current thread (Thread.currentThread().getContextClassLoader()
) whereas the main class was loaded by module's class loader (jdk.internal.loader.Loader
) (right?).
Fortunately, it looks that a fix for this issue is simple - an FXMLLoader instance must be provided with a ClaasLoader that loaded the main (application) class. It can be done in the following way:
URL location = getClass().getResource("hello.fxml");
FXMLLoader fxmlLoader = new FXMLLoader(location);
fxmlLoader.setClassLoader(getClass().getClassLoader()); // <!--- it's needed
VBox box = fxmlLoader.load();
I prepared a simple app that shows how to use FXML files + layrry. Here is the link.
In addition to that, I realized that when you have JDK/JRE that contains JavaFX (e.g. https://www.azul.com/downloads/zulu-community/?version=java-15-mts&package=jdk-fx ) then working with JavaFX is much simpler. You do not have to include JavaFX modules in layryy configuration files. Still, the classLoader must be configured for the FXMLLoader because it gives access to the JavaFX classes provided by other modules as well as is able to load controllers that can be used within FXML files (which are classes from your application module).
I hope it helps.
@p-zalejko thank you for posting this analysis, this particular FXMLLoader
setup would have to be documented in Layrry's docs, in a section specific to JavaFX.
Regarding the use of a JDK/JRE + embedded JavaFX, the decisions to use this combination or external JavaFX modules is up to application developers.
Please take a look at my new article that explain how to export all modules to all modules at runtime in Java 16 and later without using any JVM parameter
I noticed a problem when when trying to launch https://github.com/carldea/worldclock/ (from @carldea) using an external Layers config file. The problem stems form the different options there are to launch a JavaFX application. I've replicated the problem with the following code
App.java
module-info.java
layers.toml
versions.properties
The error I get when running is
This is caused by invoking
launch()
in themain()
method, as shown beforeHowever if the launch procedure is changed to
Then the application class is found and launched, however it fails due to another problem related to FXML (https://github.com/moditect/layrry/issues/68). The original problem appears to be caused by different strategies involving classloaders:
launch()
relies on the context classloader to find the target class to load, which may be different from the classloader that loaded the class with the main method to begin with.launch(Class, String...)
relies on same classloader as the class with the main method.I wonder if
Layrry
would have to setup the context classloader as well. I think it does not make any changes as far as I can tell.