Как динамически загрузить документ fxml из строки И скомпилировать / создать экземпляр его контроллера из строки - PullRequest
0 голосов
/ 25 марта 2019

Я хочу создать приложение 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");
    }
}

и все работало нормально.

но теперь мой контроллер хранится в строке, поэтому я использовал эту ссылку [inmemory]: 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

Я что-то не так сделал, так как мой контроллер правильно скомпилирован / создан, но FXMLLoader не распознал его. Можете ли вы помочь, пожалуйста? Заранее спасибо.

...