'How to create a standalone .exe in Java (that runs without an installer and a JRE)
How can I make a standalone Windows executable(.exe
) for my JavaFX
project(I wrote in IntelliJ IDEA), without an installer for my program? I want the user to download the .exe
file and run it out of the box, without an installer, even if they don't have a JRE on their computer. Is this even possible? So far I've read a little about the following options:
- launch4j - It seems to copy the required JRE files alongside the
.exe
- install4j - It makes an installer, which, once runned, creates the
.exe
file.
So, if I have understood correctly, neither of these two will help me. I found this and this posts, but they don't cover my specific case. Excuse me, if I'm asking a stupid question, this is my first ever Java GUI.
Solution 1:[1]
Solution
Use warp-packer
to create a exe
out of the image and app launcher created by jlink
.
First:
- Copy warp-packer from this download link.
- Generate an image for your application using jlink.
Then, create a single file application executable. This can be done with one command (running it on a single line and using your values instead of the %%
variables):
%WARP_DIR%\warp-packer
--arch windows-x64
--input_dir %APP_JLINK_IMAGE_DIR%
--exec %APP_JLINK_LAUNCHER_BAT_FILE%
--output %APP_SINGLE_EXECUTABLE_FILE_NAME%
The command could be run from the command line manually or automatically via an appropriate build tool plugin.
jlink can be invoked using whichever means works best for your build environment; e.g. any one of: maven plugin, gradle plugin, command line utility, jpackage
utility or jpackage build tool plugin, etc.
Related Answer
This idea is not mine, it was proposed here:
Tutorial
A full tutorial example follows if more information is required.
Solution Description
This answer is long because it seeks to provide a complete example with additional contextual advice. It could be more concise. It's style is closer to a tutorial or blog post style post than to a StackOverflow answer. Hopefully the length is not intimidating and it is easy to replicate the outcome.
I was curious about this so I thought I would try it. Surprisingly to me, I was able to get it to work. So I have documented how to replicate that here.
The key is the suggestion in comments by "OH GOD SPIDERS", to use the the "warp" tool for packaging, in conjunction with other comments suggesting interfacing with jlink.
I tried to do as much as possible using the Maven build tool, so this solution is oriented towards that. You could adapt the solution to another tool chain if you prefer.
The solution example builds a JavaFX application with FXML. The example could be simpler and much smaller if it did not include FXML, but I thought it was important to show how resources work with this solution, which is why FXML is included.
Limitations
This is, by design, a Windows only build solution which must be run on a Windows machine, both at build time and at deployment and run time.
It will only work for applications that rely on Java modules that have
module-info.java
definitions. For example, it won't work for a Spring or SpringBoot application unless it is fully modular. This is, until Spring 6 or SpringBoot 3 with full Java Platform module support is released.
High Level Steps
Build the application as a Java platform modular application.
- The application MUST have no automatic dependencies (the application itself and all transitive dependencies it relies on must be defined as Java modules with properly defined module-info.java files).
Link the application to create a runtime image with a launch script.
- I used the openjfx JavaFX Maven plugin to do the linking.
Turn the runtime image with the launch script into an exe.
- This step uses the
warp-packer
tool, which can be executed via the maven exec plugin.
- This step uses the
Procedure
- Install JDK 17 (does not require a version which includes JavaFX).
- Install Maven.
- Create the project files shown below.
- Install warp to
tools\warp-packer.exe
. - Build and package the project (
mvn package
). - Run the application exe (
target/hellowarp.exe
) to test it. - Give the application exe to friends with Windows machines.
- Friends will be able to run the exe from the command line or via a double-click on the exe.
No installation of your application is required, no extraction or unzipping of any archives, no Java runtime installation and no other additional installations are required. All that is needed is to copy the exe file to a windows machine (e.g. click on a download link on the web or copy the exe out of a mail attachment), then double click on the exe it to instantly run your application.
File tree
C:\dev\hellowarp>tree /a /f . Folder PATH listing for volume Local Disk Volume serial number is 00000086 C034:A84E C:\DEV\HELLOWARP | pom.xml | +---src | \---main | +---java | | | module-info.java | | | | | \---com | | \---example | | \---hellowarp | | HelloController.java | | HelloWarp.java | | | \---resources | \---com | \---example | \---hellowarp | hello-view.fxml | \---tools warp-packer.exe
Obtaining and installing warp
Create a new directory, \tools
, in the root of your project.
Download Warp from:
And copy the warp executable (renaming it) to the following location:
\tools\warp-packer.exe
Files
pom.xml
Maven project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hellowarp</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<javafx.version>17.0.1</javafx.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--compile-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!--create linked image-->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jlink</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.hellowarp/com.example.hellowarp.HelloWarp</mainClass>
<compress>2</compress>
<noManPages>true</noManPages>
<noHeaderFiles>true</noHeaderFiles>
<stripDebug>true</stripDebug>
<launcher>${project.artifactId}</launcher>
</configuration>
</plugin>
<!--package image as an exe-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- obtain warp-packer.exe from: "https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe" -->
<executable>${project.basedir}\tools\warp-packer.exe</executable>
<arguments>
<argument>--arch</argument>
<argument>windows-x64</argument>
<argument>--input_dir</argument>
<argument>${project.build.directory}\image</argument>
<argument>--exec</argument>
<argument>bin\${project.artifactId}.bat</argument>
<argument>--output</argument>
<argument>${project.build.directory}\${project.artifactId}.exe</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
module-info.java
Java platform module definition for the application.
module com.example.hellowarp {
requires javafx.controls;
requires javafx.fxml;
opens com.example.hellowarp to javafx.fxml;
exports com.example.hellowarp;
}
HelloWarp.java
JavaFX application.
package com.example.hellowarp;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloWarp extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(
HelloWarp.class.getResource(
"hello-view.fxml"
)
);
Scene scene = new Scene(fxmlLoader.load());
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
HelloController.java
JavaFX FXML controller class.
package com.example.hellowarp;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
@FXML
private Label welcomeText;
@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to my JavaFX Application!");
}
}
hello-view.fxml
UI view definition file.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" prefWidth="250" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.hellowarp.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
Screenshot of the running hellowarp.exe
application
FAQ
There FAQ section just provides contextual information. You can ignore this section if you already know this info, or if you don't need it.
Is this an alternative distribution method to a "fat jar"?
Yes, I think so.
What would this be appropriate for?
A small-scale application distributed in an environment where you know the users are running Windows.
Can I also package my app as an MSI installer?
Yes. I did that using the akman jpackage-maven-plugin, it worked well. To limit size and scope I will not document that in this answer.
Would it be better to use a "git repo", "fat jar", a exe, a packaged installer or "zipped" image?
It depends on what you are doing.
If your target is other developers, set up an account on github, put your project there and provide a maven or gradle build file for the developers to build the app from source in their environment. Just packaging the application as a standard jar file (no fat jar), would be fine. Any jar you create could be deployed to maven central. Use a module-info.java for the jar so that it can be linked via jlink into packaged applications.
If it is a school project. It depends on the acceptance preference for the school. Perhaps they just want the code source in git, and that is all you need. Or maybe you can create a (thin) jar file (or a zip with the jar and its dependencies) which you provide, knowing that the standard school systems have all the relevant Java/JavaFX software already installed on them.
Or maybe it is a known OS environment, e.g. Windows, Mac or Linux, and you can use jpackage
to build an installable package for one (or two) of those environments.
Or, if it is windows only, this solution of packaging as an "exe" for distribution might work well.
A "fat jar" configuration is not supported for JavaFX development. I do not recommend it. You can get it to work (currently) and it can be convenient sometimes, but you will need to decide if the trade-offs involved to do that are worth it.
If you are building a commercial or popular open source desktop product, create packaged installers, using a tool like jpackage
(or one of the commercial or open source alternatives) in the appropriate format for your target platforms (e.g. msi or exe for windows, rpm and deb for linux, dmg for mac). You may choose to deploy those packaged formats to Windows or Mac app stores or Linux yum/apt repositories.
If it is a mobile deployment, use gluon mobile.
Can I use the Apache jlink Maven plugin instead of the OpenJFX Maven plugin.
The OpenJFX JavaFX Maven plugin or the akman jpackage-maven-plugin will produce the correct images at this time.
The Apache jlink Maven plugin will, currently, fail (with JavaFX 17.0.1 and Apache jlink plugin 3.1.0).
When I tried using the Apache jlink Maven plugin, it got confused by the JavaFX platform module definitions. The Apache jlink plugin started working with weird phantom module names like javafx.graphicsEmpty
that it treated as automatic modules and passed to jlink, so jlink refused to link them. I could not find a way around that issue.
When I double click on the exe, there is blank window with the name of the
exe
in the title bar in addition to my application window.
Yes. Depending on the application that could either be a minor annoyance or a show stopper.
The display of the black screen on double-click is just the way this solution, as presented here, works.
There may be a way to circumvent this, but I haven't done a lot of investigation into it. You could look at the information supplied here (which discusses various ways to hide or minimize app launcher windows in MS Windows) and see if it helps you:
If, instead of double-clicking on the app, you are running the app by typing the exe name in a command console, there is no additional screen as there is already an existing console that you were typing in.
Can I use this technique to create single file executables for other operating systems?
Yes, I believe so.
At this time, I have not tried to use this solution for anything but Windows executables.
warp-packer
is, capable of generating executables for a variety of OS systems.
To package for a non-windows machine, you would need to input the appropriate jlink
image output for the target operating system to warp-packer and then run the appropriate warp-packer utility (I believe on the target OS) to generate the single executable for execution on that target OS.
If interested, see the warp-packer and jlink documentation.
What is the size of the generated executable?
For the sample application, my generated application executable was 34 megabytes in size.
What is the startup time?
I didn't measure it, but time to startup (time to display the application GUI window after double clicking the exe) appeared to be about a second.
Could I create an exe for a non-modular Java project.
Yes probably, but that is outside the scope of what I am prepared to discuss here, and the method would be different from that described here.
Solution 2:[2]
The absolute requirement to produce an exe is not the right thing to do but if you have to, then https://docs.gluonhq.com/ is the only reasonable way to go. Otherwise you should have a look at jpackage in conjunction with jlink. And forget all this talk about fat jars and the other options. That's not how JavaFX applications are built nowadays.
Solution 3:[3]
For this you must generate a fat jar ( if your java application has dependencies ), and if it has no dependencies just leave it as it is, and then use launch4j. For creating a fat jar, do the following:
Add this bunch of code in your build.xml file:
<property name="store.jar.name" value="Master Data App"/> <property name="store.dir" value="store"/> <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/> <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/> <delete dir="${store.dir}"/> <mkdir dir="${store.dir}"/> <jar destfile="${store.dir}/temp_final.jar" filesetmanifest="skip"> <zipgroupfileset dir="dist" includes="*.jar"/> <zipgroupfileset dir="dist/lib" includes="*.jar"/> <manifest> <attribute name="Main-Class" value="sheetupdown.SheetUpDown"/> </manifest> </jar> <zip destfile="${store.jar}"> <zipfileset src="${store.dir}/temp_final.jar" excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/> </zip> <delete file="${store.dir}/temp_final.jar"/>
In your java IDE, right click on build.xml -> Run Target -> Other Targets -> package for store
You will find your fat jar inside your project in store folder.
Open launch4j
Specify output file (ending with .exe)
Specify where you fat jar is
(Add other options as needed, like: icon, jre version .... ) -Optional-
Click Build Wrapper
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Diaf Badreddine |