Tóm tắt nhanh, bạn có thể thực hiện:
Bao gồm các mô-đun JavaFX thông qua --module-path
và --add-modules
giống như trong câu trả lời của José.
HOẶC LÀ
Sau khi bạn đã thêm thư viện JavaFX vào dự án của mình (theo cách thủ công hoặc thông qua nhập maven / gradle), hãy thêm module-info.java
tệp tương tự như tệp được chỉ định trong câu trả lời này. (Lưu ý rằng giải pháp này làm cho ứng dụng của bạn có dạng mô-đun, vì vậy nếu bạn sử dụng các thư viện khác, bạn cũng sẽ cần thêm các câu lệnh để yêu cầu mô-đun của chúng bên trong module-info.java
tệp).
Câu trả lời này là một bổ sung cho câu trả lời của Jose.
Tình hình là thế này:
- Bạn đang sử dụng phiên bản Java gần đây, ví dụ: 13.
- Bạn có một ứng dụng JavaFX dưới dạng một dự án Maven.
- Trong dự án Maven của bạn, bạn đã định cấu hình plugin JavaFX và thiết lập các phụ thuộc JavaFX theo câu trả lời của Jose.
- Bạn đi tới mã nguồn của lớp chính mở rộng Ứng dụng, bạn nhấp chuột phải vào nó và thử chạy nó.
- Bạn nhận được
IllegalAccessError
liên quan đến một "mô-đun không tên" khi cố gắng khởi chạy ứng dụng.
Đoạn trích cho dấu vết ngăn xếp tạo ra IllegalAccessError
khi cố gắng chạy ứng dụng JavaFX từ Intellij Idea:
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:567)
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:567)
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:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
at org.jewelsea.demo.javafx.springboot.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(AccessController.java:391)
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)
Exception running application org.jewelsea.demo.javafx.springboot.Main
OK, bây giờ bạn đang bị mắc kẹt và không có manh mối gì đang xảy ra.
Điều đã thực sự xảy ra là:
- Maven đã tải xuống thành công các phụ thuộc JavaFX cho ứng dụng của bạn, vì vậy bạn không cần tải xuống riêng các phụ thuộc hoặc cài đặt JavaFX SDK hoặc phân phối mô-đun hoặc bất kỳ thứ gì tương tự.
- Idea đã nhập thành công các mô-đun dưới dạng phụ thuộc vào dự án của bạn, vì vậy mọi thứ biên dịch OK và tất cả các mã hoàn thành và mọi thứ hoạt động tốt.
Vì vậy, có vẻ như mọi thứ sẽ ổn. NHƯNG, khi bạn chạy ứng dụng của mình, mã trong mô-đun JavaFX không thành công khi cố gắng sử dụng phản chiếu để khởi tạo các phiên bản của lớp ứng dụng của bạn (khi bạn gọi khởi chạy) và các lớp bộ điều khiển FXML của bạn (khi bạn tải FXML). Nếu không có một số trợ giúp, việc sử dụng phản xạ này có thể không thành công trong một số trường hợp, tạo ra sự che khuất IllegalAccessError
. Điều này là do tính năng bảo mật hệ thống mô-đun Java không cho phép mã từ các mô-đun khác sử dụng phản chiếu trên các lớp của bạn trừ khi bạn cho phép rõ ràng (và trình khởi chạy ứng dụng JavaFX và FXMLLoader đều yêu cầu phản ánh trong quá trình triển khai hiện tại của chúng để chúng hoạt động đúng).
Đây là nơi mà một số câu trả lời khác cho câu hỏi này, tài liệu tham khảo module-info.java
, đi vào hình ảnh.
Vì vậy, chúng ta hãy tham gia một khóa học về lỗi trong các mô-đun Java:
Phần quan trọng là:
4.9. Mở cửa
Nếu chúng ta cần cho phép phản ánh các loại private, nhưng chúng ta không muốn tất cả mã của mình bị lộ, chúng ta có thể sử dụng lệnh opens để hiển thị các gói cụ thể.
Nhưng hãy nhớ rằng, điều này sẽ mở gói cho toàn bộ thế giới, vì vậy hãy đảm bảo đó là những gì bạn muốn:
module my.module { opens com.my.package; }
Vì vậy, có lẽ bạn không muốn mở gói của mình cho toàn thế giới, thì bạn có thể làm:
4.10. Mở… Tới
Được rồi, đôi khi phản xạ là rất tốt, nhưng chúng tôi vẫn muốn bảo mật nhiều nhất có thể từ việc đóng gói. Chúng tôi có thể mở một cách chọn lọc các gói của mình theo danh sách các mô-đun đã được phê duyệt trước, trong trường hợp này, sử dụng lệnh opens… to:
module my.module {mở com.my.package thành moduleOne, moduleTwo, v.v.; }
Vì vậy, bạn kết thúc việc tạo một lớp src / main / java / module-info.java trông giống như sau:
module org.jewelsea.demo.javafx.springboot {
requires javafx.fxml;
requires javafx.controls;
requires javafx.graphics;
opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}
Ở đâu, org.jewelsea.demo.javafx.springboot
là tên của gói chứa lớp Ứng dụng JavaFX và các lớp Bộ điều khiển JavaFX (thay thế tên này bằng tên gói thích hợp cho ứng dụng của bạn). Điều này cho người chạy Java biết rằng các lớp trong javafx.graphics
và javafx.fxml
gọi phản chiếu trên các lớp trong org.jewelsea.demo.javafx.springboot
gói của bạn là được . Khi điều này được thực hiện, và ứng dụng được biên dịch và chạy lại, mọi thứ sẽ hoạt động tốt và việc IllegalAccessError
tạo ra bởi việc sử dụng phản chiếu của JavaFX sẽ không còn xảy ra nữa.
Nhưng nếu bạn không muốn tạo tệp module-info.java
Nếu thay vì sử dụng nút Run trong thanh công cụ trên cùng của IDE để chạy trực tiếp lớp ứng dụng của bạn, bạn thay vào đó:
- Đã đến cửa sổ Maven ở bên cạnh IDE.
- Chọn mục tiêu plugin javafx maven
javafx.run
.
- Nhấp chuột phải vào đó và chọn một trong hai
Run Maven Build
hoặc Debug...
.
Sau đó, ứng dụng sẽ chạy mà không có module-info.java
tệp. Tôi đoán điều này là do plugin maven đủ thông minh để bao gồm động một số loại cài đặt cho phép ứng dụng được các lớp JavaFX phản ánh ngay cả khi không có module-info.java
tệp, mặc dù tôi không biết điều này được thực hiện như thế nào.
Để chuyển cài đặt đó sang nút Run trên thanh công cụ trên cùng, hãy nhấp chuột phải vào javafx.run
mục tiêu Maven và chọn tùy chọn Create Run/Debug Configuration
cho mục tiêu. Sau đó, bạn chỉ có thể chọn Run từ thanh công cụ trên cùng để thực hiện mục tiêu Maven.