Build Gradle with Modules so Java does not require arguments to execute

319 Views Asked by At

I am building a TornadoFx (JavaFX for Kotlin) application. I never had a problem running the application with gradle, but building it into a jar and executing said jar has been a struggle.

Through much trial and error, I have found that I cannot simply run java -jar App.jar, but instead I have to add the following arguments to add in the proper dependencies for JavaFX --module-path /usr/share/openjfx/lib/ --add-modules javafx.controls. But I would like to implement this through gradle, so that these modules are bundled with the jar so that it can be distributed and used by others much nicer.

I have tried to add the JavaFX dependencies 2 different ways, but neither worked:

  1. Implementing the OpenJFX maven artifacts as dependencies
  2. Adding includeBuild("/usr/share/openjfx/lib") to settings.gradle.kts

Thank you to anyone who is able to help out.


Below are all the details of the application and build process:

  • JDK 1.8
  • Kotlin 1.4.32
  • Gradle Kotlin DSL
  • Source Code: GitHub

Here is my build.gradle.kts

import no.tornado.fxlauncher.gradle.FXLauncherExtension

buildscript {
    repositories {
        mavenCentral()
    }
}

plugins {
    application
    kotlin("jvm") version "1.4.32"
    id("no.tornado.fxlauncher") version "1.0.20"
}

group = "com.jtschwartz"
version = "1.0.0"

val kotlinVersion: String by rootProject
val tornadoFxVersion: String by rootProject

repositories {
    mavenCentral()
}

application {
    mainClassName = "com.jtschwartz.scratchpad.ScratchpadKt"
}

configure<FXLauncherExtension> {
    applicationVendor = "Jacob Schwartz ([email protected])"
    applicationUrl = "https://storage.googleapis.com/jts-scratchpad-bucket"
    applicationMainClass = application.mainClassName
    applicationVersion = "1.0.2"
    applicationTitle = "Scratchpad"
    applicationName = "Scratchpad"
}

dependencies {
    platform("org.jetbrains.kotlin:kotlin-bom")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
    implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
    implementation("no.tornado:tornadofx:$tornadoFxVersion")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion")
}

tasks {
    compileKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
}

tasks.withType<Jar> {
    manifest {
        attributes["Main-Class"] = application.mainClassName
    }
    from(configurations.compileClasspath.get().map {if (it.isDirectory) it else zipTree(it)})
}

tasks.register<Exec>("deployToGCP") {
    dependsOn("embedApplicationManifest")
    commandLine("gsutil", "cp", "-r", "./build/libs", "gs://jts-scratchpad-bucket")
}

And this is the error I receive when java -jar App.jar is run without the necessary module arguments:

Exception in thread "main" java.lang.NoClassDefFoundError: javafx/application/Application
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    at com.jtschwartz.scratchpad.ScratchpadKt.main(Scratchpad.kt:126)
Caused by: java.lang.ClassNotFoundException: javafx.application.Application
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 19 more

0

There are 0 best solutions below