Search code examples
javajavafxtableviewfxmlclasscastexception

JavaFX Tableview holding two kinds of objects


I'm currently writing a program with JavaFX and FXML. My current problem is that I have an FXMLTableView, which should display traits of two different object-classes, Stockorder and Article, namely the name, id and price of the article and how many of that article are in stock (which is defined in stockorder). I currently have the following Code:

Stockorder:

public class Stockorder {

    private SimpleStringProperty deliveryState;
    private SimpleStringProperty stockOrderId;
    private SimpleStringProperty orderdate;
    private SimpleStringProperty deliverydate;
    private SimpleStringProperty count;
    private SimpleStringProperty itemId;
    private SimpleStringProperty itemName;

    public Stockorder(String deliveryState, String stockOrderId, String orderdate, String deliverydate, String count, String itemId, String itemName) {
        this.deliveryState = new SimpleStringProperty(deliveryState);
        this.stockOrderId = new SimpleStringProperty(stockOrderId);
        this.orderdate = new SimpleStringProperty(orderdate);
        this.deliverydate = new SimpleStringProperty(deliverydate);
        this.count = new SimpleStringProperty(count);
        this.itemId = new SimpleStringProperty(itemId);
        this.itemName = new SimpleStringProperty(itemName);
    }

    public boolean getDeliveryState() {
        return Boolean.valueOf(deliveryState.get());
    }

    public StringProperty getDeliveryStateProperty() {
        return deliveryState;
    }

    public int getStockOrderId() {
        return Integer.parseInt(stockOrderId.get());
    }

    public StringProperty getStockOrderIdProperty() {
        return stockOrderId;
    }

    public String getOrderdate() {
        return orderdate.get();
    }

    public StringProperty getOrderdateProperty() {
        return orderdate;
    }

    public String getDeliverydate() {
        return deliverydate.get();
    }

    public StringProperty getDeliverydateProperty() {
        return deliverydate;
    }

    public int getCount() {
        return Integer.parseInt(count.get());
    }

    public StringProperty getCountProperty() {
        return count;
    }

    public int getItemId() {
        return Integer.parseInt(itemId.get());
    }

    public StringProperty getItemIdProperty() {
        return itemId;
    }

    public String getItemName() {
        return itemName.get();
    }

    public StringProperty getItemNameProperty() {
        return itemName;
    }
}

Article:

public class Article {
    private final SimpleStringProperty articleNr;
    private final SimpleStringProperty name;
    private final SimpleStringProperty price;

    public Article(String articleNr, String name, String price) {
        this.articleNr = new SimpleStringProperty(articleNr);
        this.name = new SimpleStringProperty(name);
        this.price = new SimpleStringProperty(price);
    }

    public int getArticleNr() {
        return Integer.parseInt(articleNr.get());
    }

    public String getName() {
        return name.get();
    }

    public double getPrice() {
        return Double.parseDouble(price.get());
    }

    public StringProperty getArticleNrProperty(){
        return articleNr;
    }

    public StringProperty getNameProperty(){
        return name;
    }

    public StringProperty getPriceProperty(){
        return price;
    }
}

EditArticleOverviewControl (FXMLController)

public class EditArticlesOverviewController implements Initializable {

    public EditArticlesOverviewController() {
        System.out.println("EditArticleOverviewController started");

    }

    private ApplicationControl applicationControl;
    private EditOrderController editOrderController = new EditOrderController();
    private String stockOrderURL = "stockorders";
    private HttpClient client = new HttpClient();

    @FXML
    TableView<Article> tableView;

    @FXML
    TableColumn<Article, String> articleNrColumn;

    @FXML
    TableColumn<Article, String> nameColumn;

    @FXML
    TableColumn<Article, String> priceColumn;

    @FXML
    TableColumn<Stockorder, String> stockColumn;

    @FXML
    TableColumn<Stockorder, String> minStockColumn;

    @FXML
    TableColumn<Stockorder, String> addColumn;

    @FXML
    Button cancelButton;

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

        articleNrColumn.setCellValueFactory(cellData -> cellData.getValue().getArticleNrProperty());
        nameColumn.setCellValueFactory(cellData -> cellData.getValue().getNameProperty());
        priceColumn.setCellValueFactory(cellData -> cellData.getValue().getPriceProperty());
        stockColumn.setCellValueFactory(cellData -> cellData.getValue().getCountProperty());
        minStockColumn.setCellValueFactory(cellData -> cellData.getValue().getDeliveryStateProperty());
        addColumn.setCellValueFactory(cellData -> cellData.getValue().getCountProperty());
    }

    public void setApplicationControl(ApplicationControl applicationControl) {
        this.applicationControl = applicationControl;
    }

    public void setEntriesInTableView(ObservableList articlesList) {
        tableView.setItems(articlesList);
    }

    @FXML
    public void goBack() {
        System.out.println("Kein Artikel bearbeitet");
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
        //EditOrder wieder starten vom selben Order wie vorher!!
        try {
            applicationControl.openEditOrder(applicationControl.order.getOrderNr());
        } catch (Exception ex) {
            Logger.getLogger(OrdersOverviewController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

Now every time I try to run the program, I get the error:

java.lang.ClassCastException: client.Article cannot be cast to client.Stockorder

at the line where I set the cellValueFactory for stockOrder. But I can't understand why, as the column holds Stockorder and the cellValueFactory uses methods of the Stockorder class.


Solution

  • At your code,

    TableColumn<Stockorder, String> stockColumn;
    

    It means stockColumn will try to get items as Stockorder. The S of TableColumn<S, T> affects S of setCellValueFactory(Callback<TableColumn.CellDataFeatures<S,T>,ObservableValue<T>> value) and return type S of TableColumn.CellDataFeatures<S,T>::getValue().

    But actually, items in the TableView is not instance of Stockorder, so ClassCastException is thrown at runtime. All S type of TableView<S> and TableColumn<S,T> must be same.

    In this case, to show them in a TableView, there is a need to create a data model class for use it. For example:

    class RowData {
        private Stockorder stockorder;
        private Article article;
        public RowData(Arthicle article, Stockorder stockorder) {
            this.article = article;
            this.stockorder = stockorder;
        }
        public Stockorder getStockorder(){ return stockorder; }
        public Article getArticle(){ return arthicle; }
    }