Guys, I really need some guidance. I’ve written a lot of code and classes in IntelliJ IDEA for my JavaFX application, but I’m running into serious difficulties when trying to turn it into an executable .exe file.
I’ve already tried using tools like ChatGPT and DeepSeek to figure this out, but none of the solutions worked for me. So I thought I’d explain the issue here in detail — maybe someone with experience can point me in the right direction.
Here are the key points:
The project is a JavaFX application built with Maven.
I’ve embedded an SQLite database inside IntelliJ IDEA.
Below is my
pom.xmlconfiguration (including dependencies and plugins).
If anyone has successfully created an executable .exe from a Maven-based JavaFX project, I’d really appreciate your help or step-by-step guidance.
Thanks in advance!
This is my Main class, the entry to application:
package com.example.financeapp;
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.HostServices;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Objects;
public class Main extends Application {
private static HostServices hostServices;
static {
// Set JavaFX system properties to manage D3D resources better
System.setProperty("prism.forceGPU", "true");
System.setProperty("prism.verbose", "false");
System.setProperty("prism.order", "d3d,sw");
System.setProperty("prism.maxvram", "512m");
System.setProperty("prism.texture.cache.size", "50M");
System.setProperty("prism.dirtyopts", "false");
}
// @Override
// public void init() throws Exception {
// // Initialize database from resources if it doesn't exist
// DatabaseInitializer.initialize();
// }
@Override
public void init() throws Exception {
try {
// Initialize database from resources if it doesn't exist
DatabaseInitializer.initialize();
} catch (Throwable t) {
// Ensure AppData log folder exists and append the stacktrace
try {
String appData = System.getenv("APPDATA");
if (appData == null || appData.isBlank()) appData = System.getProperty("user.home");
java.io.File logDir = new java.io.File(appData, "FinanceApp");
if (!logDir.exists()) logDir.mkdirs();
java.io.File logFile = new java.io.File(logDir, "error.log");
try (java.io.PrintWriter pw = new java.io.PrintWriter(new java.io.FileWriter(logFile, true))) {
pw.println("----- init() exception: " + java.time.LocalDateTime.now() + " -----");
t.printStackTrace(pw);
}
} catch (Exception ignored) { }
// rethrow so JVM still behaves same, but we logged it
throw t;
}
}
// @Override
// public void start(Stage stage) throws Exception{
//
// try {
//
// hostServices = getHostServices();
//
// FXMLLoader loader = new FXMLLoader(getClass().getResource("LoginForm.fxml"));
// Parent root = loader.load();
//
// Scene scene = new Scene(root, 380, 550); // Balanced size
//
// scene.getStylesheets().add(Objects.requireNonNull(getClass()
// .getResource("/CSSFolder/loginForm.css")).toExternalForm());
//
// stage.setScene(scene);
// stage.initStyle(StageStyle.UTILITY);
// stage.setResizable(false);
// stage.centerOnScreen();
//
// // Set minimum size to prevent it from being too small
// stage.setMinWidth(380);
// stage.setMinHeight(550);
//
// stage.getIcons().add(new Image(Objects.
// requireNonNull(getClass().getResourceAsStream("/icons/icon.ico"))));
//
// stage.setTitle("TOEFL Galaxy - Login");
//
// FadeTransition fadeIn = new FadeTransition(Duration.seconds(1.5), root);
// fadeIn.setFromValue(0);
// fadeIn.setToValue(1);
// fadeIn.play();
//
// stage.show();
// } catch (Exception e) {
// e.printStackTrace();
// java.io.FileWriter fw = new java.io.FileWriter("C:\\Users\\sayed\\Desktop\\app_error.log");
// e.printStackTrace(new java.io.PrintWriter(fw));
// fw.close();
// throw e;
// }
//
//
// }
@Override
public void start(Stage stage) throws Exception {
try {
hostServices = getHostServices();
// Use absolute resource paths so they work from jar and jpackage runtime
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/example/financeapp/LoginForm.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root, 380, 550); // Balanced size
// Use absolute path for CSS as well
scene.getStylesheets().add(Objects.requireNonNull(getClass()
.getResource("/CSSFolder/loginForm.css")).toExternalForm());
stage.setScene(scene);
stage.initStyle(StageStyle.UTILITY);
stage.setResizable(false);
stage.centerOnScreen();
stage.setMinWidth(380);
stage.setMinHeight(550);
// Icon as resource stream (absolute)
try (InputStream is = getClass().getResourceAsStream("/icons/icon.ico")) {
if (is != null) {
stage.getIcons().add(new Image(is));
} // if null, ignore; we'll log below
} catch (Exception ex) {
// ignore - handled by outer catch so will be logged
}
stage.setTitle("TOEFL Galaxy - Login");
FadeTransition fadeIn = new FadeTransition(Duration.seconds(1.5), root);
fadeIn.setFromValue(0);
fadeIn.setToValue(1);
fadeIn.play();
stage.show();
} catch (Exception e) {
// create AppData folder for logs
try {
String appData = System.getenv("APPDATA");
if (appData == null || appData.isBlank()) appData = System.getProperty("user.home");
File logDir = new File(appData, "FinanceApp");
if (!logDir.exists()) logDir.mkdirs();
File logFile = new File(logDir, "error.log");
try (PrintWriter pw = new PrintWriter(new FileWriter(logFile, true))) {
pw.println("----- " + java.time.LocalDateTime.now() + " -----");
e.printStackTrace(pw);
}
} catch (Exception ex) {
// last resort: write to user's home
try {
File lf = new File(System.getProperty("user.home"), "FinanceApp-error.log");
e.printStackTrace(new PrintWriter(new FileWriter(lf, true)));
} catch (Exception ignore) { }
}
// rethrow so behavior is same during development, but logging is already done
throw e;
}
}
public static HostServices getHostServicesInstance() {
return hostServices;
}
public static void main(String[] args) {
launch(args);
}
}
This is my pom.xml:
<?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>FinanceApp</artifactId>
<version>1.0.0</version>
<name>FinanceApp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>21.0.8</javafx.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<main.class>com.example.financeapp.Main</main.class>
</properties>
<dependencies>
<!-- All your existing dependencies remain the same -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.42.0.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21.0.8</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>21.0.8</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>21.0.8</version>
</dependency>
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>11.2.1</version>
</dependency>
<dependency>
<groupId>net.synedra</groupId>
<artifactId>validatorfx</artifactId>
<version>0.6.1</version>
</dependency>
<dependency>
<groupId>org.kordamp.ikonli</groupId>
<artifactId>ikonli-javafx</artifactId>
<version>12.3.1</version>
</dependency>
<dependency>
<groupId>org.kordamp.bootstrapfx</groupId>
<artifactId>bootstrapfx-core</artifactId>
<version>0.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
<!-- Better approach: Use maven-assembly-plugin instead of shade -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>