2

I am running some app with JavaFX 11 (OpenFX). The app is written in IntellijIdea and built with gradle. When running in IDE everything's ok. When building a jar it builds successfully but when I try to execute it I get an error:

Exception in thread "main" java.lang.NoClassDefFoundError: io/reactivex/subjects/Subject

To build a jar I use onslip.gradle-one-jar plugin. My gradle is the following:

plugins {
   id 'application'
   id 'org.openjfx.javafxplugin' version '0.0.5'
   id 'com.github.onslip.gradle-one-jar' version '1.0.5'
}

repositories {
   mavenCentral()
}

dependencies {
   implementation "org.openjfx:javafx-base:11:win"
   implementation "org.openjfx:javafx-graphics:11:win"
   implementation "org.openjfx:javafx-controls:11:win"
   implementation "org.openjfx:javafx-fxml:11:win"
   implementation 'com.jfoenix:jfoenix:9.0.8' 
   implementation group: 'commons-validator', name: 'commons-validator', version: '1.6' 
   implementation group: 'commons-io', name: 'commons-io', version: '2.6' 
   implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59' 
   implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1' 
   implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2' 
   implementation group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.2.5' 
   testImplementation group: 'junit', name: 'junit', version: '4.12'
}

javafx {
   modules = [ 'javafx.controls', 'javafx.fxml' ]
}

mainClassName = 'jetliner.Main'

jar {
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    manifest {
        attributes 'Main-Class': 'jetliner.Main'
    }
}

task awesomeFunJar(type: OneJar) {
    mainClass = 'jetliner.Main'
}

For jar building I run awesomeFunJar task.

Dmitry K.
  • 193
  • 1
  • 1
  • 8
  • How do you try to launch it? – Bsquare ℬℬ Jan 22 '19 at 12:56
  • I run awesomeFunJar task which executes build function from com.github.onslip.gradle-one-jar plugin – Dmitry K. Jan 22 '19 at 12:58
  • Ok for building, but when you say "when I try to execute it"? – Bsquare ℬℬ Jan 22 '19 at 13:05
  • In IDE finder I press right-click on built jar file, then select run. – Dmitry K. Jan 22 '19 at 13:15
  • There is something strange because your gradle file defines `mainClassName = 'jetliner.Main'`, but the run action seems willing to launch the `io/reactivex/subjects/Subject` one, maybe there is something wrong in your launcher configuration? – Bsquare ℬℬ Jan 22 '19 at 13:21
  • In my main class (jetliner.Main) I import `import io.reactivex.subjects.Subject` and call `subject = PublishSubject.create();` So, as I guess the jar is not packed properly and gives this exception because cannot import this class from external library `io.reactivex.rxjava2` – Dmitry K. Jan 22 '19 at 15:22
  • Yes it is certainly the case; so you should update your gradle file to package third party libraries within yours. – Bsquare ℬℬ Jan 22 '19 at 15:38
  • José answer is just perfect; he was quicker than me ;) – Bsquare ℬℬ Jan 23 '19 at 08:00

2 Answers2

2

The main problem you have in your build is related to how you define the dependencies with implementation (not compile anymore), while on the other hand, you build your jar based on configurations.compile.

Since implementation and compile are not the same, configurations.compile contains only the classes of your project, not the third party dependencies (including JavaFX).

Running the build task will generate a very small fat jar of 3 KB. Obviously this jar misses all the classes from the dependencies.

Solution

Replace in your jar task configurations.compile with configurations.compileClasspath:

jar {
    from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    manifest {
        attributes 'Main-Class': 'jetliner.Main'
    }
}

Run ./gradlew build to generate a fat jar (around 23 MB with the given dependencies), that can be run with:

java -jar build/libs/myproject.jar

Or run ./gradlew awesomeFunJar to produce a similar fat jar (21 MB), that runs with:

java -jar build/libs/myproject-standalone.jar

In both cases, the io.reactivex.rxjava2 dependencies are included.

Note 1: I haven't used this gradle-one-jar plugin before, and I don't see any major advantage in having the custom loader, all I see is that for a helloFX sample takes really too long to load it compare with the regular fat jar.

If you use it because the fat jar doesn't run, maybe you need a Launcher class, as explained here:

public class Launcher {
    public static void main(String[] args) {
        Main.main(args);
    }
}

and then replace the mainClass with jetliner.Launcher.

Note 2: The JavaFX plugin (latest version 0.0.7) uses implementation, and it takes care of adding the JavaFX dependencies, so you can simplify the build file:

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.7'
    id 'com.github.onslip.gradle-one-jar' version '1.0.5'
}

repositories {
    jcenter()
}

dependencies {
    implementation 'com.jfoenix:jfoenix:9.0.8'
    implementation group: 'commons-validator', name: 'commons-validator', version: '1.6'
    implementation group: 'commons-io', name: 'commons-io', version: '2.6'
    implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59'
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
    implementation group: 'com.sun.mail', name: 'javax.mail', version: '1.6.2'
    implementation group: 'io.reactivex.rxjava2', name: 'rxjava', version: '2.2.5'
    testImplementation group: 'junit', name: 'junit', version: '4.12'
}

javafx {
    modules = [ 'javafx.controls', 'javafx.fxml' ]
}

mainClassName = 'jetliner.Launcher'

jar {
    manifest {
        attributes 'Main-Class': 'jetliner.Launcher'
    }
    from {
        configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

task awesomeFunJar(type: OneJar) {
    mainClass = 'jetliner.Main'
}
José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Thanks a lot! Using the gradle you have provided in Note 2 I have successfully built and executed jar. The only small remark is that `mainClassName = 'jetliner.Launcher'` is needed to be kept, otherwise the app will not run with `./gradlew run` – Dmitry K. Jan 22 '19 at 20:15
  • Yes, right, I missed to paste it, sorry. I'll update the answer. – José Pereda Jan 22 '19 at 20:21
0

I had the same error while executing the extend Reports.java, I have rectified it. I simply imported the rxjava3.jar and reactive.jar into the project. It resolved my error

Ruchika Sharma
  • 648
  • 1
  • 7
  • 23
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 14 '22 at 11:33