2

I've tried to make a helper class for creating a JavaFX TableView containing some records:

public record Product(String id, String manufacturer, String model, String price, String quantity, String remarks) {
    public SimpleStringProperty getIdProperty() { return new SimpleStringProperty(id); }
    public SimpleStringProperty getManufacturerProperty() { return new SimpleStringProperty(manufacturer); }
    public SimpleStringProperty getModelProperty() { return new SimpleStringProperty(model); }
    public SimpleStringProperty getPriceProperty() { return new SimpleStringProperty(price); }
    public SimpleStringProperty getQuantityProperty() { return new SimpleStringProperty(quantity); }
    public SimpleStringProperty getRemarksProperty() { return new SimpleStringProperty(remarks); }
}
public class TableItems {
    private static boolean isReturnTypeSimpleStringProperty(Method method) {
        return method.getReturnType() == SimpleStringProperty.class;
    }

    private static <T> TableColumn<T, String> createTableColumn(Method method, String label) {
        TableColumn<T, String> column = new TableColumn<>(label);

        column.setCellValueFactory(cellData -> {
            try {
                return (SimpleStringProperty) method.invoke(cellData.getValue());
            } catch (Exception e) {
                return null;
            }
        });

        return column;
    }

    public static <T> TableView<T> getTableView(ObservableList<T> itemList, String... labels) {
        TableView<T> table = new TableView<>(itemList);

        Class<?> itemClass = (itemList.isEmpty()) ? Object.class : itemList.get(0).getClass();
        Method[] methods = itemClass.getMethods();

        int labelIdx = 0;
        for (Method method : methods) {
            if (isReturnTypeSimpleStringProperty(method)) {
                TableColumn<T, String> column = createTableColumn(method, labels[labelIdx]);
                table.getColumns().add(column);
                labelIdx++;
            }
        }

        return table;
    }

    @SafeVarargs
    public static <T> ObservableList<T> getObservableList(T...items) {
        return FXCollections.observableArrayList(List.of(items));
    }
}

But when I try to insert some sample data:

ObservableList<Product> list = TableItems.getObservableList(
    new Product("1", "Samsung", "Oddysey", "1000", "30", null),
    new Product("2", "Samsung", "Oddysey", "1000", "30", null),
    new Product("3", "Samsung", "Oddysey", "1000", "30", null),
    new Product("4", "Samsung", "Oddysey", "1000", "30", null),
    new Product("5", "Samsung", "Oddysey", "1000", "30", null)
);

TableView<Product> tableView = TableItems.getTableView(list, "ID", "Manufacturer", "Model", "Price", "Quantity", "Remarks");

...

Each time I run the program, the columns get sorted in a random order and the headings don't match the data anymore, for example:

tableview1

tableview2

I couldn't really find a problem similar to this, so is there a thing which I miss?

5
  • 3
    You're creating a new property instance each time you call getXXXProperty(). This is going to completely mess up the listeners that the cells register with those properties. You should instantiate each property once and return it from those methods. Commented Nov 28, 2023 at 14:36
  • 4
    Also note you are essentially replicating the functionality of the existing library class PropertyValueFactory, including all its flaws. It's not much harder to write a private static <T> TableColumn<T, String> createTableColumn(String label, Function<T, Property<String>> property) { ... } method which avoids those problems. Commented Nov 28, 2023 at 14:40
  • 4
    Neither of those comments directly address your question. The problem you report is explained directly in the Javadocs for getMethods(): "The elements in the returned array are not sorted and are not in any particular order.". Your code assumes they are magically in the same order as the labels you provide. Commented Nov 28, 2023 at 14:46
  • Noob mistake. Thank you very much. Commented Nov 28, 2023 at 18:51
  • 1
    If you follow the recommendation and example to use lambdas to define properties in cell factories for record items, detailed in: How do you use a JavaFX TableView with java records?, you won't invent all the auxiliary issues related to your presented solution that are mentioned in comments and your question. Commented Nov 28, 2023 at 22:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.