Java 11, JavaFX, Gradle, Eclipse, неприятное сообщение об ошибке

ОС: Linux Mint 18.3, Eclipse «2019-06». Обертка Gradle с использованием Gradle 5.4.

Вчера я потратил около 4 часов, пытаясь собрать проект в Eclipse, который бы фактически запускал и отображал сцену JavaFX при использовании Java 11. В конце концов мне это удалось благодаря помощи здесь.

Но это был просто стандартный «Java-проект» в Eclipse. На самом деле мне нужно разработать проект Gradle, используя Groovy в качестве основного языка.

Опять же, от того же джентльмена, Хосе Переды, я нашел этот ответ. Это делает "сборку" Gradle в порядке с приведенным ниже тестом. Но я получаю неприятное сообщение, когда использую задачу «run» плагина Gradle «application»: «Ошибка: компоненты времени выполнения JavaFX отсутствуют и необходимы для запуска этого приложения». Я получаю это независимо от того, запускаю ли я из Eclipse или из терминала.

Итак, это мой 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}"
}

Это код моего приложения:

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"
    }
}

и это мой тест:

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

        then:
        true
    }
}

Полный вывод в Терминале после "запуска" Gradle выглядит так:

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

Позже

Следовал указаниям Хосе Переды к письму в моем build.gradle. Вот что я делаю, пытаясь выполнить задачу «запустить»:

> 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

Примечание

Я считаю, что это не дубликат любого ответа, в котором не упоминается Gradle. У меня это работает при обычном запуске Java.


person mike rodent    schedule 26.09.2019    source источник
comment
JavaFX больше не входит в состав Java 11. Вы должны включить его отдельно.   -  person jbx    schedule 27.09.2019
comment
Вам не хватает аргументов виртуальной машины; модули JavaFX должны быть в --module-path, а необходимые модули должны быть включены в --add-modules. Это можно добавить к задаче run, и это должно сработать. В качестве альтернативы вы можете сделать толстую банку (как во втором ответе, который вы связали). Однако вы можете упростить все это, используя плагин JavaFX gradle, например, в здесь. Я предлагаю вам также прочитать руководство по началу работы.   -  person José Pereda    schedule 27.09.2019


Ответы (1)


Причина проблемы:

Ошибка: компоненты среды выполнения JavaFX отсутствуют и необходимы для запуска этого приложения.

уже был дан ответ несколько раз (в том числе с помощью Gradle), но поскольку вы все еще используете «старый» подход для включения зависимостей JavaFX, вместо использования плагина JavaFX, я объясню, как это исправить.

Ошибка

Если вы проверите документацию JavaFX для Eclipse, раздел IDE (модульный или не- модульные проекты), этому вопросу есть четкое объяснение:

Ошибка JavaFX

Или, другими словами, зависимости JavaFX являются модульными и должны быть добавлены в путь модуля.

Первое решение

Если вы продолжите читать, вы сразу же найдете объяснение, как это исправить (при условии, что вы не используете инструменты сборки):

Решение JavaFX

Однако, поскольку вы используете Gradle, решение необходимо адаптировать для включения в ваш файл сборки.

Вот как это было сделано до с использованием подключаемого модуля JavaFX:

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'
        ]
    }
}

Теперь вы можете запустить:

./gradlew run

Кстати, вы все еще можете увидеть здесь сборка примера HelloFX, указанного в документации, перед использованием плагина.

Подключаемый модуль JavaFX

Плагин JavaFX для Gradle был создан именно для того, чтобы иметь дело со всем "стандартным кодом" в файл сборки.

Если вы сейчас посмотрите документацию для Eclipse, разделы Gradle (модульные или немодульные) или тот же обновленный sample вы увидите, что файл сборки упрощен до следующего:

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'

В вашем случае вам просто нужно адаптировать это к вашему файлу сборки, например:

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" ]
}

и запустите:

./gradlew run
person José Pereda    schedule 27.09.2019
comment
Большое спасибо. Я изменил свой файл сборки точно так, как вы сказали для плагина. Я все еще получаю исключение. См. Обновление вопроса. Естественно, сейчас (или завтра) я посмотрю, работает ли это с Java (без Groovy). Я также попробую старый подход. - person mike rodent; 28.09.2019
comment
Класс приложения должен быть общедоступным. См. это. - person José Pereda; 28.09.2019
comment
Спасибо. Я только что обнародовал это. Никаких кубиков, такое же исключение. - person mike rodent; 28.09.2019
comment
Еще раз спасибо. Нет: сбой компиляции: неожиданный токен. Возможно, теперь метод launch может принимать только 1 параметр. Придется проверить источник. Кстати, должна ли версия JavaFX совпадать с версией Java? Вы поставили 13, я пробовал и 11, и 13. Завтра еще поэкспериментирую. Ваша помощь неоценима, еще раз спасибо. - person mike rodent; 28.09.2019
comment
Существует _ 1_ метод. Вы можете использовать JavaFX 11, 12 или 13. - person José Pereda; 28.09.2019
comment
Наконец-то он заработал с этим плагином ... большое спасибо. Я буду продолжать читать об этом. Я немного удивлен, что в строке build.gradle всего две строки: modules = [javafx.controls, javafx.fxml] ... а как насчет javafx-base и javafx-graphics? Тайна. В любом случае еще раз спасибо за терпение. - person mike rodent; 28.09.2019
comment
Рад, что это сработало для вас. По поводу modules переходные разрешаются плагином. См. здесь: например, элементы управления включают основу и графику. - person José Pereda; 28.09.2019