#javafx #fxml #fxmlloader #dynamic-class-loaders
#javafx #fxml #fxmlloader #загрузчики динамических классов
Вопрос:
Я хочу создать приложение javafx, в котором документ fxml и его контроллер хранятся в базе данных. Благодаря jewelsea я использую этот код для динамической загрузки документа fxml :
String fxmlDocument = "<?xml version="1.0" encoding="UTF-8"?>n"
"n"
"<?import javafx.scene.control.Button?>n"
"<?import javafx.scene.layout.BorderPane?>n"
"n"
"n"
"<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.ControllerClass">n"
" <center>n"
" <Button fx:id="button" mnemonicParsing="false" onAction="#onButtonClicked" text="Button" BorderPane.alignment="CENTER" />n"
" </center>n"
"</BorderPane>";
FXMLLoader loader = new FXMLLoader();
BorderPane layout = (BorderPane) loader.load(
new ByteArrayInputStream(fxmlDocument.getBytes())
);
Мой контроллер был впервые сохранен в ControllerClass.java файл
package main;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
public class ControllerClass {
public Button button;
public void onButtonClicked(ActionEvent event){
System.out.println("Button's clicked");
}
}
и это сработало нормально.
но теперь мой контроллер хранится в строке, поэтому я использовал эту ссылку [в памяти]:https://github.com/trung/InMemoryJavaCompiler чтобы скомпилировать и создать экземпляр моего контроллера следующим образом:
StringBuilder fxmlController = new StringBuilder();
fxmlController.append("package main;n");
fxmlController.append("import javafx.scene.control.Button;n");
fxmlController.append("import javafx.event.ActionEvent;n");
fxmlController.append("import java.util.ArrayList;n");
fxmlController.append("import java.util.List;n");
fxmlController.append("public class ControllerClass {n");
fxmlController.append(" public Button button;n");
fxmlController.append(" public void onButtonClicked(ActionEvent event){n");
fxmlController.append(" System.out.println("ControllerClass called");");
fxmlController.append(" }");
fxmlController.append(" public List<String> test() {");
fxmlController.append(" List<String> supplierNames = new ArrayList<String>();");
fxmlController.append(" supplierNames.add("sup1");");
fxmlController.append(" supplierNames.add("sup2");");
fxmlController.append(" supplierNames.add("sup3");");
fxmlController.append(" supplierNames.add("sup4");");
fxmlController.append(" System.out.println(supplierNames.get(3));");
fxmlController.append(" return supplierNames;");
fxmlController.append(" }");
fxmlController.append("}");
Class<?> controllerClass = InMemoryJavaCompiler.newInstance().ignoreWarnings().compile("main.ControllerClass", fxmlController.toString());
List<?> listSize = (List<?>) controllerClass.getMethod("test").invoke(controllerClass.newInstance());
System.out.println("listSize.size()=" listSize.size());
Когда я запускаю код, результатом является:
sup4
res.size()=4
Это означает, что контроллер правильно скомпилирован и создан, НО если я помещу документ fxml и контроллер, динамически скомпилированный / созданный / загруженный вместе, я получу ошибку
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:748)
Caused by: javafx.fxml.LoadException:
unknown path:7
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.access$700(FXMLLoader.java:103)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:922)
at javafx.fxml.FXMLLoader$InstanceDeclarationElement.processAttribute(FXMLLoader.java:971)
at javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:220)
at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:744)
at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
at main.Main.start(Main.java:111)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
... 1 more
Caused by: java.lang.ClassNotFoundException: main.ControllerClass
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:920)
... 16 more
Exception running application main.Main
Process finished with exit code 1
Проблема в том, :
Caused by: javafx.fxml.LoadException:
unknown path:7
Я сделал что-то не так, поскольку мой контроллер правильно скомпилирован / создан, но он не настроен загрузчиком FXML?
Не могли бы вы помочь, пожалуйста?
Заранее спасибо.
Комментарии:
1. Примечание: Используйте
StringBuilder
вместоStringBuffer
, если вы выполняете операции записи из нескольких потоков. Также в этом случае объединение всех строк, используемыхв одном выражении (например,
String s = a b ...;
), на самом деле было бы более производительным, поскольку объединение строк может быть выполнено во время компиляции.2. @fabian : Спасибо за совет. Я изменю StringBuffer на StringBuilder.