0

I want to build a javafx app where the fxml document and its controller both are stored in a database. Thanks to jewelsea, I use this code to load the fxml document dynamically :

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())
);

My controller was first stored in ControllerClass.java file

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

and it worked fine.

but now my controller is stored in a string so I used this link [inmemory]:https://github.com/trung/InMemoryJavaCompiler to compile and instantiate my controller like this:

        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());

When I run the code, the result is:

sup4
res.size()=4

That means, the controller is correctly compiled and instantiated BUT if I put the fxml documement and the controller dynamically compiled/instantiated/loaded together I got in error

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

The issue is :

Caused by: javafx.fxml.LoadException: 
unknown path:7

Did I do something wrong as my controller is correctly compiled/instantiated but it's not recongnized by the FXMLLoader. Can you help please ? Thanks in advance.

tkp
  • 1
  • 2
  • Side note: Use `StringBuilder` instead of `StringBuffer`, if you do writing operations from multiple threads. Also in this case concatenating all the strings using `+` in a single expression (e.g. `String s = a+b+...;`) would actually be more performant, since the string concatenation could be done at compile time. – fabian Mar 25 '19 at 00:06
  • @fabian : Thanks for the advice. I'll change StringBuffer to StringBuilder. – tkp Mar 26 '19 at 11:56

0 Answers0