JavaFX 11: IllegalAccessError เมื่อสร้างป้ายกำกับ

คำถามนี้น่าจะเกี่ยวกับปัญหาเดียวกันกับอันนี้ แต่ดูเหมือนว่าผู้ถามคนนั้นไม่ได้เพิ่มข้อมูลเพียงพอที่จะรับคำตอบที่เป็นประโยชน์

ฉันกำลังพยายามเรียกใช้แอปพลิเคชัน JavaFx ด้วย JDK และ JavaFx SDK เวอร์ชัน 11.0.2

รหัสนี้ทำงานตรงตามที่คาดไว้ โดยทำให้เกิดหน้าต่างว่าง:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    public void start(Stage primaryStage) throws Exception {
        StackPane root = new StackPane();
        primaryStage.setScene(new Scene(root, 420, 420));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

อย่างไรก็ตาม หากฉันพยายามเพิ่มป้ายกำกับให้กับ StackPane ก็จะมีข้อยกเว้นเกิดขึ้น

import ...
import javafx.scene.control.Label;

public class Main extends Application {

    public void start(Stage primaryStage) throws Exception {
        StackPane root = new StackPane();
        root.getChildren().add(new Label("42"));
        primaryStage.setScene(new Scene(root, 420, 420));
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

การติดตามสแต็กที่สร้างมีลักษณะดังนี้ (บรรทัดที่ 13 ใน Main คือตำแหน่งที่สร้างป้ายกำกับ):

Exception in Application start method
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: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalAccessError: superclass access check failed: class com.sun.javafx.scene.control.ControlHelper (in unnamed module @0xbbd2743) cannot access class com.sun.javafx.scene.layout.RegionHelper (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.scene.layout to unnamed module @0xbbd2743
    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:174)
    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 javafx.scene.control.Control.<clinit>(Control.java:86)
    at sample.Main.start(Main.java:13)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
    ... 1 more
Exception running application sample.Main

ฉันกำลังใช้งาน IntelliJ Idea เวอร์ชันล่าสุดบน Kubuntu ฉันดาวน์โหลด Oracle JDK และ JavaFX จากเว็บไซต์อย่างเป็นทางการ

ฉันใส่ javafx-sdk-11.0.2 ไว้ในไดเร็กทอรี /usr/lib/jvm/ และ jdk-11.0.2 อยู่ในไดเร็กทอรีเดียวกัน

ใน IntelliJ Idea ฉันเชื่อว่าฉันเลือก JDK ถูกต้องแล้ว และฉันได้เพิ่ม /usr/lib/jvm/javafx-sdk-11.0.2/lib เป็นไลบรารีแล้ว

IntelliJ Idea ใช้คำสั่งนี้เพื่อเปิดแอปพลิเคชัน (แยกเพื่อให้อ่านง่าย):

/usr/lib/jvm/jdk-11.0.2/bin/java
  -Djava.library.path=/usr/lib/jvm/javafx-sdk-11.0.2/lib
  --add-modules javafx.base,javafx.graphics
  --add-reads javafx.base=ALL-UNNAMED
  --add-reads javafx.graphics=ALL-UNNAMED
  -javaagent:/opt/jetbrains/idea-IU-183.4886.37/lib/idea_rt.jar=36031:/opt/jetbrains/idea-IU-183.4886.37/bin
  -Dfile.encoding=UTF-8
  -classpath
    /home/rm/IdeaProjects/JfxPlayground/out/production/JfxPlayground
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/src.zip
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx-swt.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.web.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.base.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.fxml.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.media.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.swing.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.controls.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.graphics.jar
  -p
    /usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.base.jar
    :/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.graphics.jar
  sample.Main

ฉันยังไม่ได้แก้ไขตัวเลือก VM ใด ๆ

ฉันจะแก้ไขข้อผิดพลาดนี้ได้อย่างไร มันเป็นข้อผิดพลาดใน JavaFx หรือไม่?


person Reinis Mazeiks    schedule 21.01.2019    source แหล่งที่มา
comment
เมื่อรันด้วยโมดูล คุณต้องไม่ใช้การประกาศ classpath และในทางกลับกัน   -  person Dragas    schedule 13.12.2020


คำตอบ (4)


คุณได้ให้คำอธิบายเกี่ยวกับปัญหาของคุณแล้ว:

ฉันยังไม่ได้แก้ไขตัวเลือก VM ใด ๆ

เนื่องจาก JavaFX 11 ไม่ได้เป็นส่วนหนึ่งของ JDK อีกต่อไป คุณจึงต้องใช้ JavaFX SDK (เหมือนที่คุณทำอยู่) จาก ที่นี่ หรือใช้ Maven/Gradle เพื่อดึงข้อมูลโมดูล JavaFX จาก Maven Central

จากนั้น คุณต้องเพิ่ม SDK เป็นไลบรารี เพื่อให้ IntelliJ สามารถค้นหาคลาส JavaFX ได้

แต่เมื่อคุณทำสิ่งนั้นเสร็จแล้ว และเนื่องจาก Jars ของ JavaFX เป็นโมดูล คุณยังคงต้องทำสองสิ่ง:

  • ทำให้โมดูล JavaFX พร้อมใช้งานสำหรับโมดูลพาธของคุณ
  • กำหนดโมดูลที่คุณจะเพิ่มในโครงการ

ขึ้นอยู่กับเอาต์พุต IntelliJ ของคุณ จะมีการเพิ่มตามค่าเริ่มต้น javafx.graphics และ javafx.base:

--add-modules javafx.base,javafx.graphics

-p /usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.base.jar
:/usr/lib/jvm/javafx-sdk-11.0.2/lib/javafx.graphics.jar

(โปรดทราบว่า -p เหมือนกับ --module-path)

สิ่งนี้จะอธิบายว่าทำไมโปรเจ็กต์ของคุณจึงรันในกรณีแรก เมื่อคุณไม่มีการควบคุมที่เพิ่มเข้าไปในฉาก มีเพียง StackPane ที่เป็นของ javafx.graphics โมดูล แต่จะล้มเหลวโดยมีข้อยกเว้นที่โพสต์เมื่อคุณเพิ่ม Label ที่เป็นของ javafx.controls โมดูล

มีการกล่าวหลายครั้ง: คุณ ต้อง เพื่อตั้งค่าตัวเลือก VM ที่จำเป็นสำหรับโครงการของคุณ

เริ่มต้นด้วยการอ่านเอกสารประกอบที่ https://openjfx.io/openjfx-docs/ รวมถึง IntelliJ doc ส่วน Non-modular project สำหรับ IDE ของคุณ และอ่านตอนที่ 4 เพิ่มตัวเลือก VM

ตัวเลือก VM

ดังนั้นคลิกที่ Run -> Edit Configurations และเพิ่ม:

-p /usr/lib/jvm/javafx-sdk-11.0.2/lib --add-modules javafx.controls

สมัครแล้วรัน ปัญหาจะหมดไป

person José Pereda    schedule 21.01.2019
comment
มีวิธีทำสิ่งเดียวกันโดยไม่ระบุตัวเลือก VM หรือไม่ - person user2914191; 15.02.2019
comment
@ user2914191Execute javafx:run จากหน้าต่าง Maven - person ItachiUchiha; 02.08.2019
comment
แทนที่จะดาวน์โหลด JavaFX SDK หรือไลบรารี ตัวเลือกอื่นคือการใช้ JDK ที่มีไลบรารี JavaFX/OpenJFX ผลิตภัณฑ์ดังกล่าวอย่างน้อยสองรายการ: LibericaFX จาก BellSoft และ JDK FX บิวด์ของ Azul Platform Core จาก Azul Systems - person Basil Bourque; 05.06.2021

ฉันจะใช้ gradle และปลั๊กอิน javafx สำหรับสิ่งนั้น

apply plugin: "org.openjfx.javafxplugin"

javafx {
    version = "11"
    modules = ["javafx.base", "javafx.controls", "javafx.graphics"
}
person Beowolve    schedule 13.10.2020

ตัวเลือกอื่นอาจมีประโยชน์ โดยเฉพาะอย่างยิ่งหากคุณวางแผนที่จะจัดแพคเกจแอปพลิเคชันของคุณเป็นขวดไขมัน

ขอขอบคุณคำตอบนี้

แทนที่จะแก้ไขตัวเลือก vm คุณสามารถสร้างคลาส Main อื่นซึ่งไม่ขยาย javafx.application.Application และเรียกวิธีการเริ่มต้นแอปพลิเคชันของคุณจากที่นั่น ลองดังต่อไปนี้:

public class App extends Application
{

    @Override public void start(Stage stage)
    {
        // all the stuff necessary
    }

    // Method called "main" here for experimental purposes.
    // But for production use you may decide to call it, "run" for example.
    // Exact name does not matter.
    public static void main(String[] args)
    {
        App.launch();
    }

}

// This class must NOT extend Application. It is a wrapper only.
public class Runner
{
    public static void main(String[] args)
    {
        // Starter method from previous class
        App.main(args);
    }
}

การพยายามเรียกใช้ App.main() ด้วยการกำหนดค่าเริ่มต้น (VM options เป็นฟิลด์ว่าง) จะทำให้เกิดข้อผิดพลาด ในขณะที่ Runner.main() ดำเนินการได้สำเร็จ

เพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้น คุณอาจเปรียบเทียบคำสั่งรัน java (แนวคิดจะพับคำสั่งเหล่านั้นตามค่าเริ่มต้น) ที่พบในหน้าต่าง Run หรือ Debug

person Boris    schedule 30.03.2021

ตรวจสอบ JAVA_HOME ของคุณ, JAVA_HOME'version ต้องเป็น jdk9+ หรือ jdk11+

person 远星河    schedule 25.05.2020