-1

OS: Linux Mint 18.3, Eclipse "2019-06". Gradle wrapper using Gradle 5.4.

Yesterday I spent about 4 hours trying to put together a project in Eclipse which would actually run and display a JavaFX Scene when using Java 11. I managed it in the end due to help from here.

But this was just a bog-standard "Java project" in Eclipse. What I actually need to do is develop a Gradle project, using Groovy as the main language.

Again, from the same gentleman, José Pereda, I found this answer. This does a Gradle "build" OK with the test below. But I get a nasty message when I use the Gradle "application" plugin's task "run": "Error: JavaFX runtime components are missing, and are required to run this application". I get this whether I run from inside Eclipse or from a Terminal.

So this is my build.gradle:

plugins {
     id 'java-library'
     id 'groovy'
     id 'eclipse'
     id 'application'
     id 'java'
}
mainClassName = 'core.App'
group 'Project'
version '1.0'
sourceCompatibility = 1.11
repositories {
     mavenCentral()
}
def currentOS = org.gradle.internal.os.OperatingSystem.current()
def platform
if (currentOS.isWindows()) {
     platform = 'win'
} else if (currentOS.isLinux()) {
     platform = 'linux'
} else if (currentOS.isMacOsX()) {
     platform = 'mac'
}
dependencies {
     api 'org.apache.commons:commons-math3:3.6.1'
     implementation 'com.google.guava:guava:27.0.1-jre'
     testImplementation 'junit:junit:4.12'
     implementation 'org.codehaus.groovy:groovy-all:2.5.8'
     testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
     // these seemed to do the trick for a simple "Java project"
     // ... but Gradle seems to want something else (?)
     implementation "org.openjfx:javafx-base:11:${platform}"
     implementation "org.openjfx:javafx-graphics:11:${platform}"
     implementation "org.openjfx:javafx-controls:11:${platform}"
     implementation "org.openjfx:javafx-fxml:11:${platform}"
}

This is my application code:

import javafx.application.Application
import javafx.stage.Stage

class App extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        println "start...."
    }

    public static void main(String[] args) {
        println "about to launch..."
        launch(args);
        println "...launched"
    }
}

and this is my test:

class FuncSpec extends Specification {
    def "JavaFX should run OK"(){
        when:
        App app = new App()

        then:
        true
    }
}

Full output in Terminal after Gradle "run" is like so:

mike@M17A ~/software projects/eclipse-workspace/GrVocabSearch2019-09 $  ./gradlew run

> Task :run FAILED
Error: JavaFX runtime components are missing, and are required to run this application

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':run'.
> Process 'command '/usr/lib/jvm/java-11-openjdk-amd64/bin/java'' finished with non-zero exit value 1

Later

Followed José Pereda's indications to the letter in my build.gradle. This is what I get on trying to do a "run" task:

> Task :run FAILED
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.codehaus.groovy.vmplugin.v7.Java7$1 (file:/media/chris/W10%20D%20drive/apps/Chris.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.8/2f1e8ea55e625fe51e85ef35eb067f1d9c61772d/groovy-2.5.8.jar) to constructor java.lang.invoke.MethodHandles$Lookup(java.lang.Class,int)
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.vmplugin.v7.Java7$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
        at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Error: class jdk.internal.reflect.NativeMethodAccessorImpl is not a subclass of javafx.application.Application
        at javafx.graphics/javafx.application.Application.launch(Application.java:298)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1491)
        at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.callStatic(StaticMetaClassSite.java:62)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:55)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:196)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:208)
        at core.App.main(main.groovy:60)
        ... 11 more
Exception running application core.App

FAILURE: Build failed with an exception

Note

I believe this is not a duplicate of any answer which does not mention Gradle. I have got this working in a normal Java run.

halfer
  • 19,824
  • 17
  • 99
  • 186
mike rodent
  • 14,126
  • 11
  • 103
  • 157
  • JavaFX is not bundled any more with Java 11. You have to include it separately. – jbx Sep 26 '19 at 22:39
  • 1
    Possible duplicate of [Error: JavaFX runtime components are missing, and are required to run this application with JDK 11](https://stackoverflow.com/questions/51478675/error-javafx-runtime-components-are-missing-and-are-required-to-run-this-appli) – jbx Sep 26 '19 at 22:41
  • You are missing to include the VM arguments; the JavaFX modules should go to the `--module-path`, and you should include the required modules to `--add-modules`. This can be added to the `run` task, and that should do it. Alternatively you could make a fat jar (like in the second answer you have linked). However you can simplify all of this by using the JavaFX gradle plugin, like in [here](https://github.com/openjfx/samples/blob/master/IDE/Eclipse/Non-Modular/Gradle/hellofx/build.gradle). I suggest you read the getting started [guide](https://openjfx.io/openjfx-docs/#IDE-Eclipse) as well. – José Pereda Sep 26 '19 at 22:42

1 Answers1

1

The reason for the issue:

Error: JavaFX runtime components are missing, and are required to run this application

has been answered a number of times already (including with Gradle), but since you are still using the "old" approach to include the JavaFX dependencies, instead of using the JavaFX plugin, I'll explain how to fix this.

Error

If you check the JavaFX documentation for Eclipse, section IDE (either modular or non-modular projects), there is a clear explanation of this issue:

Error JavaFX

Or, in other words, JavaFX dependencies are modular and have to be added to the module-path.

First Solution

If you keep reading, you will find immediately an explanation on how to fix it (providing you are not using build tools):

Solution JavaFX

However, since you are using Gradle, the solution has to be adapted to be included in your build file.

This is the way it was done, before using the JavaFX plugin:

compileJava {
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'javafx.controls,javafx.fxml'
        ]
    }
}

run {
    doFirst {
        jvmArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'javafx.controls,javafx.fxml'
        ]
    }
}

Now you should be able to run:

./gradlew run

By the way, you can still see here the build of a HelloFX sample referred from the documentation, before using the plugin.

JavaFX plugin

The JavaFX plugin for Gradle was created precisely to deal with all the "boilerplate code" in the build file.

If you check now the documentation for Eclipse, sections Gradle (modular or non modular), or the same updated sample you will see that the build file is simplified to this:

plugins {
  id 'application'
  id 'org.openjfx.javafxplugin' version '0.0.8'
}

repositories {
    mavenCentral()
}

dependencies {
}

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

mainClassName = 'org.openjfx.MainApp'

In your case, you just need to adapt this to your build file, something like:

plugins {
    id 'java-library'
    id 'groovy'
    id 'eclipse'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
}

mainClassName = 'core.App'
group 'Project'
version '1.0'
sourceCompatibility = 11

repositories {
    mavenCentral()
}

dependencies {
    api 'org.apache.commons:commons-math3:3.6.1'
    implementation 'com.google.guava:guava:27.0.1-jre'
    testImplementation 'junit:junit:4.12'
    implementation 'org.codehaus.groovy:groovy-all:2.5.8'
    testImplementation 'org.spockframework:spock-core:1.2-groovy-2.5'
}

javafx {
    version = "13"
    modules = [ "javafx.controls", "javafx.fxml" ]
}

and run:

./gradlew run
José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • Thanks very much. I have changed my build file exactly as you say for the plugin. I'm still getting an exception. See update to question. Naturally enough I'm now (or tomorrow) going to see whether this works with Java (no Groovy). I'll also try the old approach. – mike rodent Sep 27 '19 at 22:00
  • The Application class _must_ be public. See [this](https://stackoverflow.com/questions/57833707/why-is-this-javafx-player-freezing/57861780#57861780). – José Pereda Sep 27 '19 at 22:07
  • Thanks. I just made it public. No dice, same Exception. – mike rodent Sep 27 '19 at 22:09
  • Thanks again. No go: compile failure: "unexpected token". It may be that the `launch` method can now only accept 1 parameter. I'd have to check source. By the way, does JavaFX version have to be the same as the Java version? You've put "13", I've tried both "11" and "13". Will do some more experimenting tomorrow. Your help is invaluable, thanks again. – mike rodent Sep 27 '19 at 22:19
  • There is a [`launch(class, args)` method](https://github.com/javafxports/openjdk-jfx/blob/develop/modules/javafx.graphics/src/main/java/javafx/application/Application.java#L226). You can use JavaFX 11, 12 or 13. – José Pereda Sep 27 '19 at 22:39
  • Finally got it working with that plugin... thanks very much. I shall continue to read up on it. I'm slightly surprised that there are only two Strings in the build.gradle line "modules = [ "javafx.controls", "javafx.fxml" ]"... what about javafx-base and javafx-graphics? Mystery. Anyway thanks again for your patience. – mike rodent Sep 28 '19 at 16:00
  • Glad it worked for you. About `modules`, the transitive ones are resolved by the plugin. See [here](https://github.com/openjfx/javafx-gradle-plugin/blob/master/src/main/java/org/openjfx/gradle/JavaFXModule.java#L46): for instance, controls includes base and graphics. – José Pereda Sep 28 '19 at 16:05