How to make a runnable jar for an application that uses JavaFX without native installers

32,943

Update, December 2019

As the answer to this topic seems to evolve and change over time (and it looks like it will continue to do so). My advice is to review the documentation at https://openjfx.io to review latest best practices for packaging JavaFX applications.

I tried to use the JavaFX ant tasks but I can't get the task to actually package up the dependent jars ... And seems to only be able to create "native bundles" which I don't want.

Current advice from openjfx.io to create a single cross-platform jar for a JavaFX application, which includes dependencies and the cross-platform JavaFX libs is to use a different build tool (e.g. Maven or Gradle rather than Ant).

Use the features of those build tools (e.g. the Maven Shade plug-in) to package your dependent jars with your code into an uber-jar.

When doing this, if you want the resultant jar to be cross platform capable, e.g. to work on Window+Mac+Linux, then you need to package all of the cross platform jars as dependencies into the uber-jar (use the appropriate JavaFX version for your project).

<dependencies>
    ...
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>13</version>
        <classifier>win</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>13</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>13</version>
        <classifier>mac</classifier>
    </dependency>
</dependencies>

The resultant jar will require a more recent Java version to work (e.g. Java 11+).


There is currently an incubating project (JEP 343: Packaging Tool), targeted for Java 14, with the following goals (these are different than what is required in the question, as the packaging tool is for creating native installers, which is specifically what the question doesn't want to do):

Create a simple packaging tool, based on the JavaFX javapackager tool, that:

  • Supports native packaging formats to give end users a natural installation experience. These formats include msi and exe on Windows, pkg and dmg on macOS, and deb and rpm on Linux.
  • Allows launch-time parameters to be specified at packaging time.
  • Can be invoked directly, from the command line, or programmatically, via the ToolProvider API.

The proposed project exists because:

To address these requirements previously, a packaging tool called javapackager was distributed with Oracle’s JDK 8. However, it was removed from Oracle’s JDK 11 as part of the removal of JavaFX.

Note, due to the update outlined above, until Java 14 is released, some of the packaging recommendations mentioned below (such as javafxpackager) only apply to, now-outdated, older Java distributions (8-10).

Also the advice on not to include Java Platform libraries is outdated. From Oracle Java 8 until Oracle Java 10, JavaFX was included in the base JRE (Java runtime environment). From Java 11 on, JavaFX is not include in the base JRE and, indeed, the platform libraries must be added to the Java module path separately. Again, review https://openjfx.io for packaging options for JavaFX applications.


Outdated info:

JavaFX packaging alternatives

  1. Follow the e(fx)clipse tutorial for creating an executable jar file for a JavaFX application using Eclipse.
  2. The Oracle java packaging ant tasks and javafxpackager tool can create executable jars (described in the Oracle documentation as standalone applications). If you cannot generate such jars using the tools, then you are likely not using the tools correctly.
  3. Require a minimum version of Java 8, where jfxrt.jar (i.e. the JavaFX classes) is on the boot class path.
  4. Use a 3rd party build tool chain such as the JavaFX Maven plugin or the JavaFX Gradle plugin.

Alternative (1), e(fx)clipse packaging, is recommended for you since you are using Eclipse.

Advice

Never try to include Java platform libraries (such as jfxrt.jar) with your application. No guide you find on the internet should ever instruct you to do such a thing (due to the obvious incompatibility between minor version issues you outlined in your question). The only exception to this rule would be if you are building a self-contained, native installed application that doesn't rely on a pre-installed JRE (which you aren't).

Share:
32,943
Bola Ibrahim
Author by

Bola Ibrahim

Updated on August 05, 2022

Comments

  • Bola Ibrahim
    Bola Ibrahim over 1 year

    I have a application that worked just fine to be run with "java -jar blah.jar" after exporting as a runnable jar from Eclipse and letting it "Package required libraries into generated JAR".

    I added some JavaFX code to pop up a web browser. Now it seems it is impossible to make a runnable jar that works across minor Java versions. When I export it as a runnable jar, it copies in jfxrt.jar that is specific to my minor version. If I run this jar using "java -jar blah.jar" for the exact matching java version (jdk1.7.0_17) then it works fine, but if I use one slightly newer (jdk1.7.0_45) then it fails to resolve swingx classes properly. So much for "write once run anywhere".

    I tried to use the JavaFX ant tasks but I can't get the task to actually package up the dependent jars. This doesn't actually include the fx:resources jars in the jar it creates, like the magic eclipse "package required libraries into generated JAR" does perfectly:

    <fx:jar destfile="${dist}/${dist.jar}"> 
            <fx:application id="BlahTesterApp" 
                mainClass="blah.MainClass" 
                toolkit="swing"/> 
    
            <fileset dir="${build}"/> 
    
            <fx:resources> 
                <fx:fileset dir="${lib}" includes="**/*.jar" />
            </fx:resources>
    
            <manifest> 
                <attribute name="Implementation-Vendor" value="My Team"/>
                <attribute name="Implementation-Title" value="Tester App"/> 
            </manifest> 
        </fx:jar> 
    

    And seems to only be able to create "native bundles" which I don't want. I don't want to make users install an rpm or a deb when they used to just be able to run the darn jar.

    I don't understand why Oracle had to introduce its own magical extra layer of deployment complexity here. Don't they want people to USE JavaFX?

  • Vusala Hasanli
    Vusala Hasanli about 5 years
    I couldn't make jar in IntelliJ because of external jars. But 4 solved problem easily. Thanks!