0

I have a Java 18, JavaFX 18 Maven project which has a lot of libraries, beside the javaFX libraries, that needs to be included in the artifact. I want to create an artifact, a jar, which contains all dependencies. I started following this video to create the jar: https://www.youtube.com/watch?v=UKd6zpUnAE4

Summarizing my steps, and referring to the steps in the video:

  1. In IntelliJ in Project Structure/Project Settings/Libraries I removed all Maven added libraries, and added C:\Program Files\Java\javafx-sdk-18.0.2\lib

  2. After, in Run/Edit Configurations... I added a VM options, and in that window I added

    --module-path "C:\Program Files\Java\javafx-sdk-18.0.2\lib"

    --add-modules javafx.controls,javafx.fxml

  3. After, in the video, "Ken" the host of the video creates a class, with a main() method, that runs the application original main() class. I did not need this step, because I already has a class that does the same.

  4. After, File/Project Structure/Project Settings/Artifact/ I added a JAR/From modules with dependencies/ and I choose the class I recently created, and shortened the path until the source folder (src)

  5. Following this step, after I clicked add (+), and added the content of "...javafx-sdk-18.0.2/bin" all dll's and everything (all files).

Here, at this point, separate from the video, I also created a folder named "jars" and put all Maven dependencies jars in that folder.

According to the video, after these steps, with a double click on the artifact the jar runs without a problem.

However, I needed I more step. My dependency jars are signed jars, so I needed to open the artifact with WinRAR and remove the *.SF, *.DSA and *.RSA files. Earlier this caused me problems so I followed the idea here: Invalid signature file digest for Manifest main attributes exception while trying to run jar file, and here: "Invalid signature file" when attempting to run a .jar

After this, everything should be fine, however not :( The jar doesn't run on double click. When I run it from command line, I receive the following error:

$ java -jar jHasher.jar
jan. 15, 2023 3:19:07 DU. com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @3a178016'
javafx.fxml.LoadException:
unknown path:53

        at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2707)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2685)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2532)
        at view.GUI.start(GUI.java:29)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
        at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
        at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:263)
        at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:54)
        at javafx.fxml.FXMLLoader$Element.applyProperty(FXMLLoader.java:523)
        at javafx.fxml.FXMLLoader$Element.processValue(FXMLLoader.java:373)
        at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:335)
        at javafx.fxml.FXMLLoader$Element.processInstancePropertyAttributes(FXMLLoader.java:245)
        at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:778)
        at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2924)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2639)
        ... 11 more
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:119)
        at java.base/java.lang.reflect.Method.invoke(Method.java:577)
        at com.sun.javafx.fxml.ModuleHelper.invoke(ModuleHelper.java:102)
        at com.sun.javafx.fxml.BeanAdapter.put(BeanAdapter.java:259)
        ... 19 more
Caused by: java.lang.UnsupportedOperationException: Cannot resolve 'win10-document'
        at org.kordamp.ikonli.AbstractIkonResolver.resolve(AbstractIkonResolver.java:61)
        at org.kordamp.ikonli.javafx.IkonResolver.resolve(IkonResolver.java:73)
        at org.kordamp.ikonli.javafx.FontIcon.setIconLiteral(FontIcon.java:251)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        ... 22 more

I have searched the following error message. I also found some posts on StackOverflow, however they are not clear to me, and I was not able to fix this issue. Please, guide me how to proceed. All suggestions are highly appreciated.

Thend
  • 95
  • 7
  • 1
    Note that the "unsupported JavaFX configuration" warning and the `UnsupportedOperationException` error are most likely unrelated to each other. The former has to do with how executable JARs are placed on the class-path, but [JavaFX only supports being loaded from the module-path](https://stackoverflow.com/a/67854230/6395627). As for the error, seems like some resources or provider configuration files failed to be included in the fat JAR file (the latter possibly failed to merge properly). See https://github.com/kordamp/ikonli/issues/11 – Slaw Jan 15 '23 at 20:45
  • 1
    "_In IntelliJ in Project Structure/Project Settings/Libraries I removed all Maven added libraries, and added C:\Program Files\Java\javafx-sdk-18.0.2\lib_" -- I strongly suggest you do **not** do this. If you're going to use Maven, then you should rely on Maven for pretty much everything. Let Maven handle dependencies. Let Maven handle building your JAR; don't use IntelliJ to build your JAR. See the [Maven Shade Plugin](https://maven.apache.org/plugins/maven-shade-plugin/). And look at [this comment](https://github.com/kordamp/ikonli/issues/11#issuecomment-449963861) to the linked issue. – Slaw Jan 15 '23 at 20:48
  • 1
    With all that said, I also suggest you at least consider an alternative deployment strategy. JavaFX and so-called fat/uber JAR files do not go well together. As mentioned, JavaFX only supports being loaded from the module-path. But fat/uber JAR files are placed on the class-path, and JAR files do not support multiple modules in one file. See the "Packaging" section of the FAQs in the [JavaFX tag wiki](https://stackoverflow.com/tags/javafx/info) for ideas. Personally, I would consider using [jpackage](https://docs.oracle.com/en/java/javase/19/jpackage/packaging-overview.html). – Slaw Jan 15 '23 at 20:52
  • @Slaw Hi Slaw, thank you for your suggestions. So, I will restore everything before changed for this video. Also, I read some forum posts that I should use jlink and jpackage, but they are new to me. Are they related to each other? Do I have to use both? About the ikonli jar, i have checked the link but my project builds successfully in intelliJ. Do you think that the FXML could not load because a dependency missing? As I remember there is a ikonli-win10-pack-12.3.1-javadoc.jar that I did not add. Maybe that is the problem? – Thend Jan 16 '23 at 07:31
  • `jlink` is used to create a custom run-time image. It's essentially a way to create a custom JRE with only the code needed by the application (including third-party code). The caveat is that all code involved must be modular. `jpackage` takes a custom run-time image and creates native executables and installers, so that the application looks like any other application to the operating system. But despite the fact that `jpackage` makes use of `jlink`, it is capable of working with non-modular code. And note you don't have to use `jlink` directly, as `jpackage` will use it behind-the-scenes. – Slaw Jan 16 '23 at 19:54
  • And note, if it wasn't clear already, `jlink` / `jpackage` create a "self-contained application". That is, it embeds the JRE with your application. This means the end user doesn't have to have Java or JavaFX (or any other dependency) installed. It also means you have to build a package for each targeted operating system, because `jlink` / `jpackage` create platform-specific applications. – Slaw Jan 16 '23 at 19:57
  • As for the `ikonli` dependency, I'm not surprised the fat/uber JAR manages to build without errors. That's not the problem. The problem seems to be that stuff is _missing_ from the fat/uber JAR file. My guess is a missing or incomplete [provider configuration files](https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/util/ServiceLoader.htm) (i.e., the `META-INF/services/`), based on the issue I linked previously. If a provider is not listed in the appropriate config file, then `ikonli` won't be able to find it, even if the provider itself is included in the fat/uber JAR file. – Slaw Jan 16 '23 at 20:00
  • Javadoc is only developer documentation. You would not want to muddle it as part of your app distribution. – jewelsea Jan 18 '23 at 05:42
  • Ikonli has info on [creating fat jars that rely on ikonli](https://kordamp.org/ikonli/#_creating_a_fat_jar) and there is similar info for [JavaFX apps packaged as a jar](https://stackoverflow.com/questions/52653836/maven-shade-javafx-runtime-components-are-missing), with the cautions already mentioned in comments and the linked answer. – jewelsea Jan 18 '23 at 05:46

1 Answers1

0

After several hard day, I was able to create the executable jar. I'd like to share the know-how with you.

After 5th step, skipping the WinRAR for removing the *.SF, *.DSA and *.RSA files. I added maven-shade-plugin to my pom.xml. The shade plugin can automatically remove these unwanted files, but unfortunately by itself cannot create a runnable JAR, because throws again exceptions and doesn't run on double click (JavaFX 18 Maven IntelliJ: Graphics Device initialization failed for: d3d, sw Error initializing QuantumRenderer: no suitable pipeline found).

To avoid this exception and include the unlocated/missing JavaFX files we have to repack the already packed JAR. To do that, I used the spring-boot-maven-plugin. After setting up the plugins (code below), you have to run the plugins with maven in a correct order! My maven command was the following: mvn clean package spring-boot:repackage

That it, finally the created JAR (JAR of the JAR) can run on double click.

My pom.xml's corresponding parts:

  1. Shade plugin setting:

     <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-shade-plugin</artifactId>
         <version>3.4.1</version>
         <executions>
             <execution>
                 <phase>package</phase>
                 <goals>
                     <goal>shade</goal>
                 </goals>
                 <configuration>
                     <transformers>
    
                         <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
    
                         <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                             <mainClass>controller.Start</mainClass>
                         </transformer>
    
                     </transformers>
                     <minimizeJar>true</minimizeJar>
                     <filters>
                         <filter>
                             <artifact>*:*</artifact>
                             <excludes>
                                 <exclude>META-INF/*.SF</exclude>
                                 <exclude>META-INF/*.DSA</exclude>
                                 <exclude>META-INF/*.RSA</exclude>
                             </excludes>
                         </filter>
                     </filters>
                 </configuration>
             </execution>
         </executions>
     </plugin>
    
  2. The Spring-boot-maven-plugin setting (this should be placed outside the plugins section, at the very end of the pom.xml):

     <pluginManagement>
         <plugins>
             <plugin>
                 <!-- mvn clean package spring-boot:repackage -->
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <executions>
                     <execution>
                         <goals>
                             <goal>repackage</goal>
                         </goals>
                         <configuration>
                             <classifier>spring-boot</classifier>
                             <mainClass>
                                 controller.Start
                             </mainClass>
                         </configuration>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
     </pluginManagement>
    

Make sure to run the plugins in the correct order, as mentioned above! I found this resource very useful: https://www.baeldung.com/spring-boot-repackage-vs-mvn-package

Thend
  • 95
  • 7