FXGL: NoClassDefFoundError when calling FXGL.play("drop.wav") - java

I am trying to follow the second tutorial https://github.com/AlmasB/FXGL/wiki/Adding-Images-and-Sounds-%28FXGL-11%29 and it appears that i get an error when i run the application. I use gradle run or run it in eclipse, without the sound everything works fine.
My project structure looks like this:
I use openJDK 11.0.3 and linux mint 19.1 64-bit.
It is just basically the same program as in the tutorial, i get the following exception:
Message: javafx/scene/media/AudioClip Type: NoClassDefFoundError
Method: DesktopAudioService.loadAudioImpl() Line:
DesktopAudioService.kt:28
My build.gradle is pretty straight forward i guess; the gradle init and the dependencies:
plugins {
id 'application'
id 'java-library'
id 'org.openjfx.javafxplugin' version '0.0.7'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
api 'org.apache.commons:commons-math3:3.6.1'
implementation 'com.google.guava:guava:27.0.1-jre'
// Use JUnit test framework
testImplementation 'junit:junit:4.12'
compile 'com.github.almasb:fxgl:11.1-beta'
}
javafx {
version = "12"
modules = [ 'javafx.controls' ]
}
mainClassName = 'game.idea.BasicGameApp'
I expect the sound to be played when clicking 'f' on my keyboard without crashing the program. I also hope for some background explanation what causes the error.

You use the JavaFX Gradle plugin and set the modules in your build like this:
javafx {
version = "12.0.1"
modules = [ 'javafx.controls' ]
}
This means that the plugin will add to your project the javafx.base, javafx.graphics and javafx.controls modules, with the version and correct classifier based on your platform.
If you check your external libraries, you won't find any other JavaFX module implementation, but you might find the "empty" modules that FXGL is using:
So Base, Graphics and Controls use the Mac classifier (in my case), and the version I've set (12.0.1), while the other modules (FXML, Media and Swing) are empty modules added from FXGL (see for instance the Media dependency).
When you run your project, the Media classes are not there, so when you try to play the sound you get the reported exception:
Fatal exception occurred: java.lang.NoClassDefFoundError : javafx/scene/media/AudioClip
E: com.almasb.fxgl.audio.impl.DesktopAudioService.loadAudioImpl(DesktopAudioService.kt:28)
E: com.almasb.fxgl.audio.impl.DefaultAudioService.loadAudio(DefaultAudioService.kt:29)
E: com.almasb.fxgl.app.AssetLoader.loadSound(AssetLoader.kt:247)
E: com.almasb.fxgl.dsl.FXGL$Companion.play(FXGL.kt:228)
E: com.almasb.fxgl.dsl.FXGL.play(FXGL.kt)
E: game.idea.BasicGameApp$5.onActionBegin(BasicGameApp.java:61)
The solution is quite easy: just add the missing modules to your build:
javafx {
version = "12.0.1"
modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.swing', 'javafx.media' ]
}
Finally, as an aside, you can use 'com.github.almasb:fxgl:11.3'.

If you are using OpenJDK , then JavaFx might not be available. This will be the reason for the exception. Change to Oracle JDK if you are using windows. On linux, there are other ways with OpenJDK itself.
Refer to this post JavaFX and OpenJDK for some details on how-to.

Related

JavaFX FatJar using Gradle and IntelliJ

I've tried everything by now, so I hope someone in here can tell me more...
Im trying to produce an executable .jar from a IntelliJ Gradle JavaFX project. I used the standard setup that IntelliJ provided, I changed the Gradle.build file however.
The new file I got from here: Non-Modular Gradle (openjfx.io)
I have a main class that has some basic code in it and a launcher class that does not extend Application and is specified as the Main class in the jar manifest.
For now I only use javafx.controls and basically everything is as the example they provided here.
When doing the ./gradlew jar command I get the error:
no module-info.java found
Which - as I understand - is not required if I use the Non-Modular approach?
However if I add it I get the error:
Entry module-info.class is a duplicate but no duplicate handling strategy has been set.
I tried every other option out there, all of them lead to either the 2. error or the jar was produced but not executable due to the fact that it can't find the Application class...
Any help is greatly appreciated.
I just want to point out that I've never really used Gradle before and have never formally learned any coding, but can fiddle my way around usually.
For the sake if it my build file:
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.9' // this is old right?
}
repositories {
mavenCentral()
}
dependencies {
/* uncomment for cross-platform jar: */
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:win"
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:linux"
runtimeOnly "org.openjfx:javafx-graphics:$javafx.version:mac"
}
javafx {
version = "16"
modules = [ 'javafx.controls' ]
}
mainClassName = 'main.class.with.Code'
jar {
manifest {
attributes 'Main-Class': 'main.class.with.Launcher'
}
from {
// this is what causes the module duplicate error I think (at least it did in my other tries)
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}

Building FatJar for JavaFX with gradle and intellij, getting NoClassDefFOundError

I have set up an OpenJDK 12 project in IntelliJ (2019.2) using the built-in Gradle support. To design the GUI I'm using JavaFX 12. I have followed and read the setup guide several times, I have no issues running the program in my IDE, the issue is when I try to build a .jar file for distribution that I run into problems. I have not been able to find a solution that works so far and I've searched QUITE a lot, nearly tearing my hair out over this. Currently when i try to run my jar file with java -jar "jarName".jar I get the following error:
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:1016)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
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:521)
at com.CAM.Starter.main(Starter.java:6)
Caused by: java.lang.ClassNotFoundException: javafx.application.Application
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 10 more
I have tried moving my main class to a separate one that doesn't extend Application, which is what gives the above error. Without moving my Main class I get a different error.
My build.gradle looks like this currently:
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
group 'ClassicAddonManager'
version '0.2'
sourceCompatibility = 11
repositories {
mavenCentral()
}
javafx {
version = "12.0.2"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile 'net.sourceforge.htmlunit:htmlunit:2.13'
compile group: 'com.google.code.gson', name: 'gson', version: '2.7'
compile group: 'net.lingala.zip4j', name: 'zip4j', version: '1.2.4'
}
jar {
manifest {
attributes 'Main-Class': 'com.CAM.Starter'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
If I have my main method extending Application then I get an error stating that my main class could not be found even though I can see it is present in the generated .jar file.
All I'm trying to do, is to generate a file that a friend with no knowledge of programming could run. Ideally, a file that they could run without having to install Java first. I know it should be possible to do this, but Gradle is new to me so I'm not sure if that is what is causing all this headache. Is there potentially an easier way to deploy? Especially given that this is a solo-project?
EDIT
I have tried the modular part of the guide. Doing that I have over 100 error when attempting to build. They are all something in the vein of:
javafx.graphicsEmpty reads package org.xml.sax from both xml.apis and java.xml
If you want to do a fat jar using Gradle but not a shadow plugin, usually you will do:
jar {
manifest {
attributes 'Main-Class': 'com.CAM.Starter'
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
However, there is an important fact: compile is deprecated, and the JavaFX plugin uses implementation by default.
As a consequence, configuration.compile might be empty, or at least, it won't contain the JavaFX classes.
The solution is to check the runtimeClasspath configuration, as we will have all the classes there, and we can make the fat jar:
jar {
manifest {
attributes 'Main-Class': 'com.CAM.Starter'
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
This is explained in the OpenJFX docs, https://openjfx.io/openjfx-docs/#modular, section non-modular projects, subsection gradle.
Once you have your fat jar, you can run it with:
java -jar yourFatJar.jar
Note that double-clicking on it won't work, as explained in detail here, so it can be convenient to create a small batch instead.
A better solution is to do a modular project and use jlink to create a runtime image (it also includes a launcher script). You can distribute this image to other users that don't have even JDK installed. With gradle, you can just include the 'org.beryx.jlink' plugin, like in this sample.
And you can also use the early version of jpackage to create and distribute an installer.

Cannot find symbol error: Lombok 1.18.6 does not work with Gradle 5.2.1, JDK 10

Builds with Gradle 5.2.1 and Lombok 1.18.6 dependency are failing with JDK 10. It seems Lombok annotation are not being processed appropriately. I keep getting "cannot find symbol" error across various Java files in my source. Any thoughts on why this might be happening? I found that a defect has already been created: https://github.com/rzwitserloot/lombok/issues/1572
I am using:
Java JDK 10
Gradle 5.2.1
Lombok 1.18.6
Thanks.
I found the following work around for this issue using a plugin for processing Lombok annotation in compile time.
I had to perform the following steps in build.gradle:
1) Add id "net.ltgt.apt" version "0.15" to plugins section.
2) Add maven { url 'https://projectlombok.org/edge-releases' } to repositories section.
3) Add the following to dependencies section:
compileOnly 'org.projectlombok:lombok:edge-SNAPSHOT'
apt 'org.projectlombok:lombok:edge-SNAPSHOT'
compileOnly 'org.projectlombok:lombok:1.18:6'
annotationProcessor 'org.projectlombok:lombok:1.18:6'
4) Add a task:
tasks.withType(JavaCompile) {
options.annotationProcessorPath = configurations.apt
}
This lets your build complete successfully.
Update 03/29/2019: This workaround also works with Gradle 5.3, Java JDK 10
Thanks.

gradle project sync failed even after upgrading gradle plugin

Gradle project sync failed and did not get answers from other related questions. Here are the details of my situation.
Initial sync attempt yielded the following error message:
Unsupported method: BaseConfig.getApplicationIdSuffix().
The version of Gradle you connect to does not support that method.
To resolve the problem you can change/upgrade the target version of Gradle you connect to.
Alternatively, you can ignore this exception and read other information from the model.
I have Android Studio 3.0. The build.gradle file includes the following dependency:
classpath 'com.android.tools.build:gradle-experimental:0.2.1'
The gradle-wrapper.properties file includes the following distribution URL:
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
According to https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#update_gradle I need to make some changes.
First, update the Gradle version for Android Studio 3.0 in gradle-wrapper.properties:
distributionUrl=\
  https://services.gradle.org/distributions/gradle-4.1-all.zip
(I believe the backslash right after the equal sign is an error and did not make that change.)
Second, add the following buildscript repository to build.gradle:
google()
Third, change the build.gradle dependency:
classpath 'com.android.tools.build:gradle:3.0.1'
The second and third changes apply the latest version of the Android plug-in.
When I try to sync after these changes it fails again with the following new error:
Plugin with id 'com.android.model.application' not found.
The error refers to the first line of build.gradle:
apply plugin: 'com.android.model.application'
What is happening and why? I recently added NDK to Android Studio. The project I'm trying to sync includes C code. I'm not completely certain I added NDK correctly. I wonder if that could be part of the problem.
First, the gradle-wrapper.properties is incorrect. You must include \ in it. It should be something like this:
#Sat Jun 17 17:47:18 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
Then, add the experimental classpath to project build.gradle. Something like this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha4"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
Check the Experimental Plugin User Guide for details.
Go to your build.gradle version or update it
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
You should change you dependencies classpath
All steps are here :
Open build.gradle and change the gradle version to the recommended version:
classpath 'com.android.tools.build:gradle:1.3.0' to
classpath 'com.android.tools.build:gradle:2.3.2'
Hit 'Try Again'
In the messages box it'll say 'Fix Gradle Wrapper and re-import project' Click that, since the minimum gradle version is 3.3
A new error will popup and say The SDK Build Tools revision (23.0.1) is too low for project ':app'. Minimum required is 25.0.0 - Hit Update Build Tools version and sync project
A window may popup that says Android Gradle Plugin Update recommended, just update from there.
Now the project should be runnable now on any of your android virtual devices.
Make sure your Gradle version is compatible with your Android Gradle Plugin.
https://stackoverflow.com/questions/24795079
https://developer.android.com/studio/releases/gradle-plugin#updating-gradle

Intellij Idea 13 UI Designer and automatic Gradle building

I've used the Intellij UI Designer to create forms for a project. Everything works fine when I'm building with idea as it handles compiling the forms for me, but as we recently switched to using Gradle for building it hasn't been possible to produce an executable jar file yet.
My google-fu has led me to several posts that explains that an ant script is needed to compile (eg link, link2, link3 ,and the one i ended on following: link4)
My project is a multi-module setup.
root build.gradle
subprojects {
apply plugin: 'java'
apply plugin: 'idea'
repositories {
mavenCentral()
}
}
supproject build.gradle
apply plugin:'application'
mainClassName = "dk.OfferFileEditor.OfferFileEditorProgram"
configurations {
antTask
}
dependencies {
compile 'org.json:json:20140107'
compile project(":Shared:HasOffers Api")
//dependencies for java2c
antTask files('../../lib/javac2-13.1.1.jar', '../../lib/asm4-all-13.1.1-idea.jar', '../../lib/forms_rt-13.1.1.jar')
antTask group: 'org.jdom', name: 'jdom', version: '1.1'
}
task compileJava(overwrite: true, dependsOn: configurations.compile.getTaskDependencyFromProjectDependency(true, 'jar')) {
doLast {
println 'using java2c to compile'
project.sourceSets.main.output.classesDir.mkdirs()
ant.taskdef name: 'javac2', classname: 'com.intellij.ant.Javac2', classpath: configurations.antTask.asPath
ant.javac2 srcdir: project.sourceSets.main.java.srcDirs.join(':'),
classpath: project.sourceSets.main.compileClasspath.asPath,
destdir: project.sourceSets.main.output.classesDir,
source: sourceCompatibility,
target: targetCompatibility,
includeAntRuntime: false
}
}
But even though the compilation is successfull, a Nullpointer exception is thrown the first time I try to access one of the fields the UI Designer created. So something is not being compiled correctly.
I'm probably missing some setting, but after unsuccesfully pouring several hours into forums and google I still haven't found any solution.
So I made this a lot more complicated than needs be.
To make it work you need to change two things in your project.
A setting in IDEA 13.1.5
Settings -> GUI Designer -> Generate GUI into: Java source code
This makes IntelliJ IDEA add 3 methods into the bottom of your forms:
$$$setupUI$$$()
$$$setupUI$$$()
$$$getRootComponent$$$()
If they are missing try recompiling your project after you change the setting.
Add the missing classes
Intellij has a jar called forms_rt.jar, and I found mine in {IntelliJ IDEA Root}\lib. And renamed it to "forms_rt-13.1.1.jar"
This needs to be included during compile time to your project. If you are using Gradle as I did you could copy it to {project root}/lib and add a flatfile repository like so:
repositories {
mavenCentral()
flatDir dirs: "${rootDir}/lib"
}
After that you need to include it in your project gradle file:
dependencies {
compile name: 'forms_rt', version: '13.1.1'
}
After that it should be possible to build it both in IntelliJ IDEA and Gradle.
IntelliJ IDEA 2019.1
I found this issue still exists. It's at least somehow documented now:
If your build actions are delegated to Gradle, GUI Designer will not generate Java source code.
So by disabling the according setting
Build, Execution, Deployment | Build Tools | Gradle | Runner | Delegate IDE build/run actions to gradle
I was able to build and run the project successfully. Note that I didn't need any other settings or additional libraries from the answers above. I let Generate GUI into be set to Binary class files.
The forms_rt library is in mavenCentral.
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22forms_rt%22
Once you have configured IntelliJ to update the SourceCode it is sufficient to just add the library to the dependencies in your build.gradle.
dependencies {
compile 'com.intellij:forms_rt:7.0.3'
}
Idea 2019.2
It seems like IntelliJ changed the settings UI when updating from 2019.1 to 2019.2, as the menu entry mentioned by Tom isn't there anymore.
I got it fixed by setting Build and run using: to IntelliJ Idea. I also changed Run tests using: to IntelliJ Idea to avoid problems while testing.
Both settings are located under File | Settings | Build, Execution, Deployment | Build Tools | Gradle.
I figured out an updated version of the gradle build workaround for a new project - https://github.com/edward3h/systray-mpd/blob/master/build.gradle
Probably won't use the form designer again though.
These are the relevant parts:
repositories {
mavenCentral()
maven { url "https://www.jetbrains.com/intellij-repository/releases" }
maven { url "https://jetbrains.bintray.com/intellij-third-party-dependencies" }
}
configurations {
antTask
}
dependencies {
implementation 'com.jetbrains.intellij.java:java-gui-forms-rt:203.7148.30'
antTask 'com.jetbrains.intellij.java:java-compiler-ant-tasks:203.7148.30'
}
task compileJava(type: JavaCompile, overwrite: true, dependsOn: configurations.compile.getTaskDependencyFromProjectDependency(true, 'jar')) {
doLast {
project.sourceSets.main.output.classesDirs.each { project.mkdir(it) }
ant.taskdef name: 'javac2', classname: 'com.intellij.ant.Javac2', classpath: configurations.antTask.asPath
ant.javac2 srcdir: project.sourceSets.main.java.srcDirs.join(':'),
classpath: project.sourceSets.main.compileClasspath.asPath,
destdir: project.sourceSets.main.output.classesDirs[0],
source: sourceCompatibility,
target: targetCompatibility,
includeAntRuntime: false
}
}
The dependency versions for jetbrains libraries are found via https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html?from=jetbrains.org#using-intellij-platform-module-artifacts and https://www.jetbrains.com/intellij-repository/releases/

Categories

Resources