After countless days of trying to find an answer to my question, I've decided to post it here. I've been developping a monitoring application for my company, and as I'm about to distribute it, the jar file seems not runnable. The exact error is :
Error: Could not find or load main class net.nephty.connectwisemonitoring.app.Main
Caused by: java.lang.ClassNotFoundException: net.nephty.connectwisemonitoring.app.Main
The Main class contains the main method that runs the application. It works fine when being run, meaning there is no compile time error.
I am building this project using Gradle. Here is my build.gradle file :
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.24.1'
}
group 'net.nephty'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.9.0'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'net.nephty.connectwisemonitoring'
mainClass = 'net.nephty.connectwisemonitoring.app.Main'
}
javafx {
version = "18.0.2"
modules = ['javafx.base', 'javafx.controls', 'javafx.fxml', 'javafx.graphics', 'javafx.media', 'javafx.swing', 'javafx.web']
}
dependencies {
implementation('org.controlsfx:controlsfx:11.1.1')
implementation('com.dlsc.formsfx:formsfx-core:11.5.0') {
exclude(group: 'org.openjfx')
}
implementation('org.kordamp.ikonli:ikonli-javafx:12.3.1')
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.4.0'
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}
task fatJar(type: Jar) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes 'Start-Class': 'net.nephty.connectwisemonitoring.app.Main'
attributes 'Main-Class': 'net.nephty.connectwisemonitoring.app.Main'
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
exclude 'META-INF/*.RSA'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
}
jar {
manifest {
attributes(
'Main-Class': 'net.nephty.connectwisemonitoring.app.Main'
)
}
}
Because of the error I've had, I've tried unpacking the jar to see if my code was in the right location. When unpacking the jar, I see that there is no net/nephty/... directory and cannot find my code anywhere.
The manifest is being build properly, as all the specified attributes end up in the file.
I've looked up this, this, this and this post, as well as many many more but none seemed to solve my issue.
I've tried making a new project and re-writing my build.gradle file but to no avail.
When I use gradle jar, the code ends up in the jar, which is what I want. Unfortunately, gradle jar doesn't include dependencies AFAIK.
If you'd like a minimal reproducible example, you can try creating a new project using gradle and use my build.gradle file as well as a basic main class located in the correct path. If you'd like to have the code sample, I've uploaded it here.
I feel like I'm really really close to solving this, but I can't find the source of the issue. My best guess would be that it stems from this part of the build.gradle file :
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
where the runtimeClasspath would be wrong but I can't find anything about this.
Specs :
------------------------------------------------------------
Gradle 7.5
------------------------------------------------------------
Build time: 2022-07-14 12:48:15 UTC
Revision: c7db7b958189ad2b0c1472b6fe663e6d654a5103
Kotlin: 1.6.21
Groovy: 3.0.10
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.4 (Oracle Corporation 17.0.4+11-LTS-179)
OS: Windows 10 10.0 amd64
Thanks in advance for your time. Let me know if I missed some information I should share.
EDIT : I've tried changing the duplicate strategy but that didn't do anything.
Related
Running the compiled executable jar with java --module-path {$SDK_PATH} add-modules javafx.controls, javafx.fxml, javafx.media -jar frogger.jar is fine. However, executing the compiled exe from launch4j will not run or crashed silently I would say. Is there anything that I'm doing wrong here? Is there any way to see the error?
I've copied and pasted the unzipped jre in bundled directory. So I'm guessing the issue is either my launch4j configuration in build.gradle is wrong or the jre version is wrong.
the jre that I pasted in is AdoptOpenJDK windows x64 jdk-15.0.1+9
plugins {
id 'java'
id 'org.openjfx.javafxplugin' version '0.0.9'
id 'application'
id 'edu.sc.seis.launch4j' version '2.4.9'
}
group 'com.tsb'
version '1.0'
mainClassName = 'com.tsb.frogger.core.Launcher'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'junit:junit:4.12'
}
javafx {
version = '15'
modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.media']
}
task myJavadocs(type: Javadoc) {
source = sourceSets.main.allJava
}
jar {
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
launch4j {
// headerType = "console"
mainClassName = "$mainClassName"
icon = "${projectDir}/icons/frogger.ico"
bundledJrePath = "jre"
bundledJre64Bit = true
}
Rather than using launch4j, I recommend that you take a look at jpackage, which is available in JDK 14 and 15. See Packaging Tool User's Guide. Note that for Windows you will also need to download the WiX toolset.
I have a relatively straightforward modular project, and I've already set all of the options that I've found in the documentation as well as in different answers or articles such as How to force gradle to add dependencies to the module path instead of the class path in eclipse? and others.
I'm getting a module not found exception:
java.lang.module.FindException: Module gdx.backend.lwjgl not found, required by com.myproject.client
I only get this exception when running my application through gradle's application:run task. When I run it in IntelliJ or using the runtime image generated by the Badass JLink plugin, everything runs fine. After hours of debugging and building command lines by hand I was able to figure out that the difference between a correctly started program and what gradle does, is that everything else starts the program using the --module-path option while Gradle INSISTS on producing the following command line, no matter what I do in my build.gradle files:
Starting process 'command 'C:\Tools\java\bin\java.exe''. Working directory: C:\repos\pv-core\master\pv-client Command: C:\Tools\java\bin\java.exe -Dfile.encoding=windows-1252 -Duser.country=FR -Duser.language=fr -Duser.variant -cp C:\Users\accou\.gradle\caches\modules-2\files-2.1\com.badlogicgames.gdx\gdx-backend-lwjgl\1.9.11\3c094feb74e2aef14e30e988326612ee75387c8f\gdx-backend-lwjgl-1.9.11.jar;[...] --module com.myproject.client/com.myproject.client.ClientStarter
Successfully started process 'command 'C:\Tools\java\bin\java.exe''
Error occurred during initialization of boot layer
java.lang.module.FindException: Module gdx not found, required by com.myproject.client
My gradle files contain the following:
Root file:
subprojects {
apply plugin: "java"
java {
modularity.inferModulePath = true
}
targetCompatibility = '11'
sourceCompatibility = '11'
repositories {
mavenLocal()
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
jcenter()
google()
}
test {
useJUnitPlatform()
testLogging {
events 'PASSED', 'FAILED', 'SKIPPED'
}
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}
version = '0.0.1'
ext {
appName = 'MyProject'
gdxVersion = '1.9.11'
box2DLightsVersion = '1.4'
aiVersion = '1.8.0'
artemisVersion = '2.3.0'
junitVersion = '5.4.2'
slf4jVersion = '1.8.0-beta2'
}
}
project(':pv-core') {
dependencies {
}
}
Client project (application):
plugins {
id 'org.beryx.jlink' version '2.22.3'
id 'application'
}
jlink {
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher{
name = 'hello'
jvmArgs = ['-Dlog4j.configurationFile=./log4j2.xml']
}
}
ext.moduleName = 'com.myproject.client'
group = 'com.myproject.client'
//mainClassName = 'com.myproject.client.PVClientStarter'
application {
mainModule = 'com.myproject.client'
mainClass = 'com.myproject.client.ClientStarter'
}
apply plugin: 'java-library'
dependencies {
api "com.badlogicgames.gdx:gdx:$gdxVersion"
api "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
api "com.esotericsoftware.spine:spine-libgdx:3.6.53.1"
api "com.underwaterapps.overlap2druntime:overlap2d-runtime-libgdx:0.1.0"
api "com.kotcrab.vis:vis-ui:1.3.0"
api "net.dermetfan.libgdx-utils:libgdx-utils:0.13.4"
//api "de.tomgrill.gdxfacebook:gdx-facebook-core:1.4.1"
//api "de.tomgrill.gdxdialogs:gdx-dialogs-core:1.2.5"
api "com.github.czyzby:gdx-kiwi:1.9.1.9.6"
api "com.github.czyzby:gdx-lml:1.9.1.9.6"
api "com.github.czyzby:gdx-lml-vis:1.9.1.9.6"
api "de.golfgl.gdxgamesvcs:gdx-gamesvcs-core:1.0.2"
compile "com.badlogicgames.gdx:gdx-ai:$aiVersion"
compile "com.badlogicgames.gdx:gdx-controllers:$gdxVersion"
//compile "com.esotericsoftware:kryo:5.0.0"
compile "kryonet:kryonet:2.21"
testCompile 'org.testng:testng:7.3.0'
}
test {
useTestNG()
//testLogging.showStandardStreams = true
testLogging {
events "passed", "skipped", "failed"
}
}
compileJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs += [
'--module-path', classpath.asPath
]
classpath = files()
}
}
Any idea as to how I can possibly (FINALLY) tell gradle to go with --module-path rather than -cp ?!
I think I just figured it out randomly. I kept messing with the gradle files and eventually removed the java blocks containing the statements modularity.inferModulePath = true (despite this being the main advice given in the gradle docs....!), moved up the compileJava block above dependencies and the jlink plugin configuration and it ended up working somehow.
Lots of black magic involved in all this stuff, is the feeling I'm left with after a couple of days of fighting vs modules & gradle tbh..
EDIT: actually I didn't address the root cause of the problem, gradle is still using -cp over --module-path, but the changes I just described above here eventually lead to the gradle successfully launching my application, yet STILL with the -cp option. So I'm still very much interested in having gradle do a proper, JPMS-compliant, module launch (instead of a classpath launch).
The model Gradle introduced for dealing with modules in Java is based on inferring whether or not the current project code is a module or not.
This means that your application needs to have either a module-info or a Automatic-Module-Name entry in its manifest.
Further details in the documentation.
I am looking for javafx 10 or newer. I currently have javafx-sdk-11 and trying to make my programme a single runnable jar file, but apparently since javafx 11, that option isn't available anymore.
So I have to go to the terminal and type the following line to run it :
java --module-path /path/to/javafx/javafx-sdk-11.0.2 or another/lib --add-modules javafx.controls,javafx.fxml,javafx.graphics,javafx.web -jar /path/to/GUI_Music_Gen.jar
Since I can't find older versions of javafx available for download, I ask for your help. If anybody can help me, let me know. Thanks in advance.
Btw, I don't know if this will be an issue for compatibility, but I run macOS X.
I would recommend using dependency management like grade or maven to run JavaFX and Build a working Jar.
I can offer you this build.gradle for a working JavaFX project:
buildscript {
dependencies {
classpath group: 'de.dynamicfiles.projects.gradle.plugins', name: 'javafx-gradle-plugin', version: '8.7.0'
classpath 'org.openjfx:javafx:11'
}
repositories {
mavenLocal()
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
}
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
sourceCompatibility = 11
targetCompatibility = 11
repositories {
jcenter()
mavenCentral()
}
// configure here
mainClassName = "your.app.main"
publishing {
publications {
mavenAar(MavenPublication) {
from components.java
afterEvaluate {
artifact javadocJar
artifact sourcesJar
}
}
}
}
javafx {
version = "11"
modules = ['javafx.controls', 'javafx.fxml', 'javafx.graphics']
}
sourceSets {
main.java.srcDir "src/main/java"
main.resources.srcDir "src/main/resources"
}
dependencies {
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:27.0.1-jre'
testImplementation 'junit:junit:4.12'
// use java fx just like a regular dependency :)
implementation 'org.openjfx:javafx:11'
compile group: 'org.openjfx', name: 'javafx', version: '11.0.2'
}
// important Configure your project
jar {
manifest {
attributes(
'Main-Class': 'your.app.main'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
compileJava {
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls,javafx.fxml,javafx.graphics'
]
println options.compilerArgs
}
}
Just replace "your.project.main" with your actual main class and everything should run fine.
Also it is really important that your Main class does not extend from Application.
It should only Launch the Application.
I've created a JavaFX 11 app that is ready to be deployed.
I use Gradle 5.0 as my build tool and this command to compile the jar:
jar {
manifest {
attributes(
'Main-Class': 'checkmydigitalfootprint.MainApp'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Then on command line I've tried different commands to run the jar file:
java -jar CheckMyDigitalFootprint.jar
java -jar CheckMyDigitalFootprint.jar --module-path="/users/joseph/eclipse-workspace/javafx-sdk-11.0.1/lib" --add-modules=javafx.controls
java -jar CheckMyDigitalFootprint.jar --module-path="/users/joseph/eclipse-workspace/javafx-sdk-11.0.1/lib" --add-modules=javafx.controls --add-exports=javafx.graphics/com.sun.javafx.util=ALL-UNNAMED --add-exports=javafx.base/com.sun.javafx.reflect=ALL-UNNAMED --add-exports=javafx.base/com.sun.javafx.beans=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.glass.utils=ALL-UNNAMED --add-exports=javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED
But all result in the same error:
Error: JavaFX runtime components are missing, and are required to run this application
Rest of build.gradle:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.5'
id 'eclipse'
}
repositories {
mavenCentral()
}
dependencies {
/* uncomment for cross-platform jar: */
// compile "org.openjfx:javafx-graphics:11:win"
// compile "org.openjfx:javafx-graphics:11:linux"
compile "org.openjfx:javafx-graphics:11:mac"
compile 'com.jfoenix:jfoenix:9.0.8'
compile 'org.json:json:20180813'
compile 'com.google.api-client:google-api-client:1.23.0'
compile 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
compile 'com.google.apis:google-api-services-gmail:v1-rev83-1.23.0'
compile group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'
compile 'com.sun.activation:javax.activation:1.2.0'
compile group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
testCompile "org.testfx:testfx-core:4.0.15-alpha"
testCompile "org.testfx:testfx-junit:4.0.15-alpha"
}
javafx {
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
run {
if (osdetector.os == 'windows') {
// Temporal fix for Eclipse with JDK 1.8 and Windows
systemProperty "java.library.path", "C:\tmp"
}
}
jar {
manifest {
attributes(
'Main-Class': 'checkmydigitalfootprint.MainApp'
)
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
mainClassName = 'checkmydigitalfootprint.MainApp'
This is explained on official OpenJFX website
The solution is simple, just add following VM option:
--module-path /path/to/javafx-sdk-11.0.1/lib --add-modules=javafx.controls,javafx.fxml
for your Gradle project apply JavaFX gradle plugin
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.5'
}
add the required modules. e.g:
javafx {
modules = [ 'javafx.controls' ]
}
Specify version of JavaFX
javafx {
version = "11.0.+"
}
Hopefully this will help you :)
You solve the problem by using this
Java -jar --module-path /path/to/javafx-sdk-11.0.1/lib --add-modules=javafx.controls,javafx.fxml (path to your jar file)
I have no experience with Gradle but was having the same problem with a runnable jar giving the "JavaFX runtime components are missing...". (Using openJDK/JFX 11.) Even when the vm arguments were correctly included in the command line. The problem was the "Library handling" option for building the runnable jar. "Extract required libraries.." didn't do the job. "Package required libraries..." was the correct option for building a runnable jar file with JavaFX dependency.
To also solve this problem.....
You can create another main class aside the main class javafx provided and then call the javafx main class from the main class you created. In this way you can create an executable jar with all the javafx runtime module present and create an installer form the jar. This is mostly applicable when you are using any jdk above 8
After much research, I can't seem to get to the root of a problem I am having in generating a runnable Scala jar file using Gradle. I'm overriding the 'jar' Gradle task to create a jar file (dependencies included) that executes starting from my main class file. However, whenever I run it, regardless of what I use for a Main-Class attribute, the console throws a "Could not find or load main class" error. Here's what I have so far:
build.gradle
buildscript {
repositories {
mavenCentral()
}
}
apply plugin: 'java'
apply plugin: 'scala'
apply plugin: 'application'
repositories {
mavenCentral()
// some other repos
}
version = '1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
mainClassName = "com.test.Main"
dependencies {
// my dependencies
}
jar {
zip64 = true
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
src/main/scala/com/test/Main.scala
package com.test
object Main {
def main(args: Array[String]): Unit = {
print("Hello world");
}
}
In fact, when I run "java tf test.jar", it shows "com/test/Main.class" in the root of the jar! Am I missing some important class path info or something? I'm running Java 1.8 on macOS Sierra using Gradle 3.5. Any help is appreciated. Thanks!
I had a similar problem and it turns out that my META-INF folder inside my jar file contains a few RSA, SF, and DSA files.
Once I excluded them, it worked!
here is how to based on your jar declaration
jar {
zip64 = true
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it)
}
exclude ('META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA')
}
You can use the Shadow Jar Plugin instead of your own jar definition.
Benefits of Shadow
Shadowing a project output has 2 major use cases:
Creating an executable JAR distribution
Bundling and relocating common dependencies in libraries to avoid classpath conflicts
Basic setup:
shadowJar {
baseName = 'your-app'
classifier = 'all'
version = version
configurations = [project.configurations.compile]
}
jar {
manifest {
attributes 'Main-Class': 'com.test.Main'
}
}
You can use the new syntax of Gradle Plugins:
plugins {
id 'java'
id 'scala'
id 'application'
}