I have written a simple calculator program in Javafx and scenebuilder in Eclipse IDE.
It is running well. Also I can create .JAR file by Launch4J. This jar is also running in command promt with the JVM arguments which I used in run as->argument portion
–module-path “C:Program FilesJavaopenjfx-22.0.2_windows-x64_bin-sdkjavafx-sdk-22.0.2lib” –add-modules javafx.controls,javafx.fxml
But when I am creating .exe in Launc4j that .exe file is not working.
I tried keeping the entire jdk folder, jre folder, javafx folder in my application creation folder.
In my windows under program files I have the detail below
I have the foledrs under program files as PROGRAM FILES->JAVA->JDK-1.8, JDK-22, JDK-22.0.2, JRE1.8.0_421, javafx-sdk-22.0.2.
(I have the javafx folder under program files->java->openjfx-22.0._2_windows-x64_bin-sdk->javafx-sdk-22.0.2)
Stil .exe is not working
5
Example Tree
- Use IDE NetBeans crate a JavaFX Example App.
- Add Log4j function
demofxapp
├── pom.xml
└── src
└── main
├── java
│ ├── com
│ │ └── example
│ │ └── demofxapp
│ │ ├── App.java
│ │ ├── PrimaryController.java
│ │ └── SecondaryController.java
│ └── module-info.java
├── launch4j
│ ├── DemoApp_LocalDir.xml
│ └── logo.ico
└── resources
├── com
│ └── example
│ └── demofxapp
│ ├── primary.fxml
│ └── secondary.fxml
└── log4j2.xml
module-info.java
module com.example.demofxapp {
requires javafx.controls;
requires javafx.fxml;
requires org.apache.logging.log4j;
opens com.example.demofxapp to javafx.fxml;
exports com.example.demofxapp;
}
App.java
Change: Only Add log4j function.
package com.example.demofxapp;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
/**
* JavaFX App
*/
public class App extends Application {
private static final Logger logger = LogManager.getLogger(App.class);
private static Scene scene;
static void setRoot(String fxml) throws IOException {
logger.info("setRoot");
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
logger.info("loadFXML");
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
logger.info("launch");
launch();
}
@Override
public void start(Stage stage) throws IOException {
logger.info("start");
scene = new Scene(loadFXML("primary"), 640, 480);
stage.setScene(scene);
stage.setTitle("DemoApp");
stage.show();
}
}
PrimaryController.java
Change: Only Add log4j function.
package com.example.demofxapp;
import javafx.fxml.FXML;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
public class PrimaryController {
private static final Logger logger = LogManager.getLogger(PrimaryController.class);
@FXML
private void switchToSecondary() throws IOException {
logger.info("switchToSecondary");
App.setRoot("secondary");
}
}
SecondaryController.java
package com.example.demofxapp;
import javafx.fxml.FXML;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
public class SecondaryController {
private static final Logger logger = LogManager.getLogger(SecondaryController.class);
@FXML
private void switchToPrimary() throws IOException {
logger.info("switchToPrimary");
App.setRoot("primary");
}
}
primary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demofxapp.PrimaryController">
<children>
<Label text="Primary View" />
<Button fx:id="primaryButton" text="Switch to Secondary View" onAction="#switchToSecondary"/>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
secondary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.demofxapp.SecondaryController">
<children>
<Label text="Secondary View" />
<Button fx:id="secondaryButton" text="Switch to Primary View" onAction="#switchToPrimary" />
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
<Appenders>
<!-- Console Appender Configuration -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</Console>
<!-- File Appender Configuration -->
<File name="File" fileName="logs/app.log" append="true">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</File>
</Appenders>
<Loggers>
<!-- Root Logger Configuration -->
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
<!-- Application Specific Logger Configuration -->
<Logger name="com.example" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Logger>
</Loggers>
</Configuration>
DemoApp_LocalDir.xml
<?xml version="1.0" encoding="UTF-8"?>
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>demofxapp.jar</jar>
<outfile>demofxapp.exe</outfile>
<errTitle>Demo FX App</errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl></downloadUrl>
<supportUrl></supportUrl>
<stayAlive>true</stayAlive>
<restartOnCrash>false</restartOnCrash>
<manifest></manifest>
<icon>logo.ico</icon>
<jre>
<path>jre</path>
<requiresJdk>false</requiresJdk>
<requires64Bit>true</requires64Bit>
<minVersion></minVersion>
<maxVersion></maxVersion>
<opt>-Dlog4j.configurationFile=conf/log4j2.xml</opt>
</jre>
</launch4jConfig>
logo.ico
you can use your icon file.
pom.xml
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demofxapp</artifactId>
<name>demofxapp</name>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>21</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>21</version>
</dependency>
<!-- Log4j2 core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<!-- Log4j2 API -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs</classpathPrefix>
<mainClass>
com.example.demofxapp.App
</mainClass>
</manifest>
<manifestEntries>
<Class-Path>conf/log4j2.xml</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<outputDirectory>${project.build.directory}libs</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- `mvn clean package exec:exec@jlink-build-jre` -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>jlink-build-jre</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>jlink</executable>
<arguments>
<argument>--strip-debug</argument>
<argument>--no-man-pages</argument>
<argument>--no-header-files</argument>
<argument>--compress=2</argument>
<argument>--module-path</argument>
<argument>${project.build.directory}/libs</argument>
<argument>--add-modules</argument>
<argument>
java.base,javafx.fxml,javafx.graphics,javafx.controls,org.apache.logging.log4j,org.apache.logging.log4j.core
</argument>
<argument>--output</argument>
<argument>${project.build.directory}/dist/app/jre</argument>
</arguments>
<workingDirectory>${project.build.directory}</workingDirectory>
</configuration>
</execution>
<!-- `mvn exec:exec@launch4j-build-app-exe` -->
<execution>
<id>launch4j-build-app-exe</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>"C:Program Files (x86)Launch4jlaunch4jc.exe"</executable>
<arguments>
<argument>${project.build.directory}distappDemoApp_LocalDir.xml</argument>
</arguments>
<workingDirectory>${project.build.directory}</workingDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<mainClass>com.example.demofxapp.App</mainClass>
</configuration>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
</execution>
<execution>
<!-- Configuration for manual attach debugging -->
<!-- Usage: mvn clean javafx:run@debug -->
<id>debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:8000
</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE debugging -->
<id>ide-debug</id>
<configuration>
<options>
<option>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</option>
</options>
</configuration>
</execution>
<execution>
<!-- Configuration for automatic IDE profiling -->
<id>ide-profile</id>
<configuration>
<options>
<option>${profiler.jvmargs.arg1}</option>
<option>${profiler.jvmargs.arg2}</option>
<option>${profiler.jvmargs.arg3}</option>
<option>${profiler.jvmargs.arg4}</option>
<option>${profiler.jvmargs.arg5}</option>
</options>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.0</version>
<executions>
<!-- Run Command
`mvn resources:copy-resources@prepare-launch4j-resources`
-->
<!-- copy-resources , after jlink-build-app-jre-->
<execution>
<id>prepare-launch4j-resources</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/app</outputDirectory>
<resources>
<resource>
<directory>src/main/launch4j</directory>
<includes>
<include>logo.ico</include>
<include>DemoApp_LocalDir.xml</include>
</includes>
</resource>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>demofxapp.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
<!-- Run Command
`mvn resources:copy-resources@prepare-launch4j-resources-conf`
-->
<!-- copy-resources , after jlink-build-app-jre -->
<execution>
<id>prepare-launch4j-resources-conf</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dist/app/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Build
mvn clean package
you can find output:
- create
demofxapp.jar
- create
libs
include dependency jar
target
├── demofxapp.jar
└── libs
├── javafx-base-21.jar
├── javafx-base-21-linux.jar
├── javafx-base-21-win.jar
├── javafx-controls-21.jar
├── javafx-controls-21-linux.jar
├── javafx-controls-21-win.jar
├── javafx-fxml-21.jar
├── javafx-fxml-21-linux.jar
├── javafx-fxml-21-win.jar
├── javafx-graphics-21.jar
├── javafx-graphics-21-linux.jar
├── javafx-graphics-21-win.jar
├── log4j-api-2.23.1.jar
└── log4j-core-2.23.1.jar
maven-jar-plugin
- config jar as executable jar
- add dependency jat to classpath
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs</classpathPrefix>
<mainClass>
com.example.demofxapp.App
</mainClass>
</manifest>
<manifestEntries>
<Class-Path>conf/log4j2.xml</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
maven-dependency-plugin
download dependency jar to target/libs
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<outputDirectory>${project.build.directory}libs</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
create app jre
mvn exec:exec@jlink-build-jre
create folder target/dist/app/jre
target
└── dist
└── app
└── jre (85 MB)
It is same as command line:
jlink ^
--module-path targetlibs ^
--add-modules java.base,javafx.fxml,javafx.graphics,javafx.controls,org.apache.logging.log4j,org.apache.logging.log4j.core ^
--strip-debug ^
--no-man-pages ^
--no-header-files ^
--compress=2 ^
--output targetdistappjre
NOTE: In Windows, the newline symbol for command-line instructions is ^
. This notation can be used to break a long instruction into multiple lines.
use exec-maven-plugin do the same thing.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- `mvn clean package exec:exec@jlink-build-jre` -->
<execution>
<id>jlink-build-jre</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>jlink</executable>
<arguments>
<argument>--strip-debug</argument>
<argument>--no-man-pages</argument>
<argument>--no-header-files</argument>
<argument>--compress=2</argument>
<argument>--module-path</argument>
<argument>${project.build.directory}/libs</argument>
<argument>--add-modules</argument>
<argument> java.base,javafx.fxml,javafx.graphics,javafx.controls,org.apache.logging.log4j,org.apache.logging.log4j.core
</argument>
<argument>--output</argument>
<argument>${project.build.directory}/dist/app/jre</argument>
</arguments>
<workingDirectory>${project.build.directory}</workingDirectory>
</configuration>
</execution>
Prepare Launch4j Work Diectory:
mvn ^
resources:copy-resources@prepare-launch4j-resources ^
resources:copy-resources@prepare-launch4j-resources-conf
Get output
target/dist/app
├── DemoApp_LocalDir.xml (*Launch4j)
├── logo.ico (*Launch4j)
├── demofxapp.jar
├── conf
│ └── log4j2.xml
└── jre
Create Launch4j EXE
mvn exec:exec@launch4j-build-app-exe
get output: demofxapp.exe
target/dist/app
├── DemoApp_LocalDir.xml (*Launch4j)
├── logo.ico (*Launch4j)
├── demofxapp.jar
├── demofxapp.exe
├── conf
│ └── log4j2.xml
└── jre
Same Terminal Command:
"C:Program Files (x86)Launch4jlaunch4jc.exe" C:UsersIEUserDocumentsdemofxapptargetdistappDemoApp_LocalDir.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- `mvn exec:exec@launch4j-build-app-exe` -->
<execution>
<id>launch4j-build-app-exe</id>
<!-- <phase>package</phase> -->
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>"C:Program Files (x86)Launch4jlaunch4jc.exe"</executable>
<arguments>
<argument>${project.build.directory}distappDemoApp_LocalDir.xml</argument>
</arguments>
<workingDirectory>${project.build.directory}</workingDirectory>
</configuration>
</execution>
Clean dist app directory
PLEASE DELETE THESE FILES.
target/dist/app
├── DemoApp_LocalDir.xml (*DELETE)
├── logo.ico (*DELETE)
├── demofxapp.jar (*DELETE)
final dist directory
app
├── demofxapp.exe
├── conf
│ └── log4j2.xml
└── jre
Now you can copy the entire app directory to other environments without JDK or JRE installed for execution.
Install App to Other Windows
- copy
app
toC:TOOLS
check jre
modules
java --list-modules
JDK, JavaFX, Log4j
Result:
C:UsersIEUser>cd C:TOOLSappjrebin
C:TOOLSappjrebin>java --list-modules
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
javafx.base@21
javafx.controls@21
javafx.fxml@21
javafx.graphics@21
[email protected]
[email protected]
[email protected]
Screen
Run exe
Check log file
You can modify conflog4j2.xml
to change log format.
Environment:
- Windows 10
- JDK 17 (OpenJDK17U-jdk_x64_windows_hotspot_17.0.11_9.msi)
- Maven 9
- Launch4j (launch4j-3.50-win32.exe)