Oscar Hurtado Morato
Oscar Hurtado Morato

Reputation: 13

External jar FXML Load Exception

I try to load a class located in an external jar using classloader. The class "FXMLbase" loads ok, but the error is triggered when the FXMLdocument.fxml try to instantiate the FXMLDocumentController. However when the "FXMLbase" is instantiate throught the JavaFXApplication5.java (located at the external jar) it works fine. Any Ideas?

Class Loader

 File file = new File("C:/Users/Os/Dropbox/CODE_OS/JavaFXApplication5/dist/JavaFXApplication5.jar");
 URLClassLoader clazzLoader = URLClassLoader.newInstance(new URL[]{file.toURI().toURL()}, this.getClass().getClassLoader());
 Class c = clazzLoader.loadClass("javafxapplication5.FXMLbase");
 PluginInterface fXMLbase = (PluginInterface) c.newInstance();
 Parent loadScreen = fXMLbase.getRoot();

FXMLbase.java -- external jar --

public Parent getRoot() {
    Parent root = null;
    try {
        System.out.println("Class Name:" + getClass().getName());           
        root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
    } catch (IOException ex) {            
        Logger.getLogger(FXMLbase.class.getName()).log(Level.SEVERE, null, ex);
    }
    return root;
}

FXMLdocument.fxml -- external jar --

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8"  fx:controller="javafxapplication5.FXMLDocumentController">
<children>
    <Button fx:id="button" layoutX="126" layoutY="90" onAction="#handleButtonAction" text="Click Me! app5" />
    <Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
</children>

FXMLDocumentController.java -- external jar --

public class FXMLDocumentController implements Initializable{    
@FXML
private Label label;    
@FXML
private void handleButtonAction(ActionEvent event) {
    System.out.println("You clicked me!");
    label.setText("Hello World!");
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    // TODO
}    
}

JavaFxApplication5.java -- external jar --

public void start(Stage stage) throws Exception {        
    FXMLbase fXMLbase=new FXMLbase();
    Parent root = fXMLbase.getRoot();
    Scene scene = new Scene(root);        
    stage.setScene(scene);
    stage.show();
}

Error:

ago 28, 2014 2:26:16 PM javafxapplication5.FXMLbase getRoot
SEVERE: null
javafx.fxml.LoadException: 
file:/C:/Users/Os/Dropbox/CODE_OS/JavaFXApplication5/dist/JavaFXApplication5.jar!/javafxapplication5/FXMLDocument.fxml:9
 ....
Caused by: java.lang.ClassNotFoundException: javafxapplication5.FXMLDocumentController

Upvotes: 1

Views: 3040

Answers (1)

James_D
James_D

Reputation: 209704

The FXMLLoader at some point has to load the controller class from the value of the fx:controller attribute in the root element of the FXML file. It looks like it is using the system class loader to do this: I think this is because the system class loader finds the FXMLLoader class and loads it, rather than the class loader used to load your FXMLBase class.

The only fix I can find for this is to explicitly set the controller class from the FXMLbase class, instead of specifying it in the FXML. This is a bit unsatisfactory; perhaps there is a better way I am missing.

Updated FXMLbase class:

public Parent getRoot() {
    Parent root = null;
    try {
        System.out.println("Class Name:" + getClass().getName());           
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        loader.setController(new FXMLDocumentController());
        root = loader.load();
    } catch (IOException ex) {            
        Logger.getLogger(FXMLbase.class.getName()).log(Level.SEVERE, null, ex);
    }
    return root;
}

and you need to remove the fx:controller attribute from the FXML file.

Upvotes: 3

Related Questions