JavaFX FXML controller ClassNotFoundException


Question

I am trying to get a TableView in JavaFX to dynamically display content.

When I run my program I get this error:

java.lang.ClassNotFoundException: UserInterfaceController

My controller is named "UserInterfaceController.java", it's under the same package as the FXML file and I have imported the package in the FXML as well. Why can't the controller be found?

FXML file:

<?import javafx.collections.*?> 
<?import javafx.geometry.Insets?>
<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.scene.layout.*?>
<?import d1example2.*?>

<GridPane alignment="center" hgap="10.0" vgap="10.0" fx:controller="UserInterfaceController"
             xmlns:fx="http://javafx.com/fxml">
     <TableView fx:id="tableView" GridPane.columnIndex="0" GridPane.rowIndex="1">
          <columns>
          </columns>    
     </TableView>
</GridPane>

Controller:

package d1example2;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Text;
import javafx.util.Callback;

public class UserInterfaceController implements Initializable {

    private Label label;
    @FXML
    private AnchorPane MainPane;
    @FXML
    private TextField FirstField;
    @FXML
    private Text TimesText;
    @FXML
    private Text EqualSign;
    @FXML
    private Text EquationResult;
    @FXML
    private TableColumn<?, ?> HalfColumn;
    @FXML
    private TableColumn<?, ?> DoubleColumn;
    @FXML
    private Button SubmitButton;

    @FXML private TableView tableView;

    @FXML
    public void initialize(URL url, ResourceBundle rb) {

    List<String> columns = new ArrayList<String>();
    columns.add("col1");
    columns.add("col2");
    TableColumn [] tableColumns = new TableColumn[columns.size()];     
    int columnIndex = 0;
    for(int i=0 ; i<columns.size(); i++) {
        final int j = i;
        TableColumn col = new TableColumn(columns.get(i));
        col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){                   
           public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {                                                                                             
                return new SimpleStringProperty(param.getValue().get(j).toString());                       
            }                   
        });
        tableView.getColumns().addAll(col);
    }       
    ObservableList<String> row = FXCollections.observableArrayList();
    ObservableList<String> row1 = FXCollections.observableArrayList();
    row.addAll("d1");
    row.addAll("d11");
    row1.addAll("d2");
    row1.addAll("d22");
    tableView.getItems().add(row);
    tableView.getItems().add(row1);
    }    

    @FXML
    private void handleButtonAction(MouseEvent event) {

    }

}

Main Class:

package d1example2;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class D1Example2 extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("FXML TableView Example");
        Pane myPane = (Pane)FXMLLoader.load(getClass().getResource("UserInterface.fxml"));
        Scene myScene = new Scene(myPane);
        primaryStage.setScene(myScene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
1
7
12/8/2013 1:34:39 PM

Accepted Answer

Reference your controller from FXML using it's fully qualified name:

fx:controller="d1example2.UserInterfaceController"

Answers to follow-up questions

Answers to the following questions explain why this is so, but you don't necessarily need to understand why if you don't want to, the following is purely informational.

Why must it be fully qualified when he has an import statement?

The imports in the FXML file are not searched when resolving the FXML controller class. The controller class type is found via the class loader (I determined this by reading the JavaFX FXMLLoader source code). The class loader requires a fully qualified name (specifically, a binary name as per the Java language specification).

Once the type is found, if no controller factory has been specified for the fxml loading, then the FXMLLoader will instantiate the controller itself using reflection, otherwise it will delegate that job to an appropriate controller factory (e.g. a controller factory that associates a controller instance based upon Spring dependency injection) but even in that instance, the appropriate type must be found and determined by the FXMLLoader first and to do that it requires a fully qualified classname for the controller.

What's the point of import statements if I need to do that anyway?

The import statements are used for resolving the Java types corresponding to the FXML elements in the document. That way, the document can contain the line:

<?import javafx.scene.layout.*?>

And you can just reference GridPane instead of javafx.scene.layout.GridPane, when you want to define a new GridPane in your FXML.

<GridPane alignment="center" ...>

Yes, potentially, the FXMLLoader could have been coded to also resolve controller classes in the same manner, but it just hasn't been written that way at the time that this answer was written.

13
8/20/2019 5:26:50 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon