Reputation: 305
I am trying to package a javafx application using javafx11, jdk11 in NetBeans 10 after a while away from the java world. Since Javafx was put out of the standard jdk and NetBeans is still being incubated at Apache, things are a bit rougher than they used to be.
Luckily I found this great tutorial and this great answer which allowed me to run a simple Hello World application from inside NetBeans.
But I can't make it work outside of the IDE : when invoked with the outputed jar, the jre gives the following error :
java.lang.NoClassDefFoundError: javafx/application/Application
So I guess I need to package a javafx runtime in the jar to be able to run it but I can't figure how to do it.
I found some pointers but they all use command lines to point to the javafx sdk, but I am not targeting machines with this sdk installed on them and would like to package everything needed (except the jre itself) in the jar.
Any help much appreciated.
Upvotes: 1
Views: 2264
Reputation: 305
I figured it out in no small part thanks to the invaluable help (and commendable patience in his comments) of José Pereda. So credit should go to him.
So, here we go :
Your jar must conform to the following specs :
Now if you can do that by any mean (Ant, Makefile, custom script, specific IDE feature...) then everything will work nicely.
First, I created a lib folder in my project and put the libs directly there (this is not necessary, just easier in my case), then I overrided the "post-jar" target in my build.xml, adding the following to create a second "dist" repository that I called "dist-portable" and built the fat jar inside :
<target name="-post-jar">
<property name="store.jar.name" value="${application.title}${application.desc}-portable"/>
<property name="store.dir" value="dist-portable"/>
<property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/>
<echo message="Packaging ${application.title}${application.desc} 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="lib" includes="*.jar"/>
<fileset dir="lib" includes="*.so"/>
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
</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"/>
</target>
Use more advanced build tools such as Maven or Gradle. I don't want to (hence the very point of my question) for they seem far too complex to be worth the bother considering I'm only doing small projects.
The "8" generation (NetBeans 8, Javafx8 and JDK8) were great pieces of software and were released not that far back in time (first half of 2014) and officially supported up til a couple of months ago : they are not ancient and... they just work out of the box without having to do anything. The "11" generation might have to mature a bit and I don't think every environment has jumped to the cutting edge JDK11 yet. The older versions can still be found and work well just about everywhere, you might consider simply using them. Just be conscious they are not being updated anymore (and this can be a security concern).
Upvotes: 3
Reputation: 88
I had the same problem a month ago. To solve it I used Maven with the following 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>{your-groupId}</groupId>
<artifactId>{your-artifactId}</artifactId>
<version>0.1-SNAPSHOT</version>
<properties>
<lwjgl.version>3.2.1</lwjgl.version>
<joml.version>1.9.12</joml.version>
<main.class>{your-package-name}.{your-main-class}</main.class>
<maven.compiler.source>1.11</maven.compiler.source>
<maven.compiler.target>1.11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- // Compiling : $ mvn clean compile assembly:single-->
<build>
<directory>outputDirectory</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>false</addClasspath>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${main.class}</mainClass>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java/{your-package-name}</directory>
<includes>
<include>sample.fxml</include>
</includes>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>13-ea+2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>13-ea+2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>13-ea+2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>13-ea+2</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.4</version>
</dependency>
</dependencies>
You can find list of all available javafx artifacts here.
All you have to do is:
Add the file module-info.java. Mine had the following content:
module {your-package-name} {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
requires javafx.base;
requires javax.json;
// Change the list to match your dependencies
opens {your-package-name};
}
Build your jar with NetBeans or via the mvn compile assembly:single
command in a terminal
Upvotes: 0