JavaFX TableView: Do I HAVE to wrap my fields in SimpleProperty?

Question

I know that TableViews and their columns depend on the fact that the represented objects have XYZProperty values and appropriate getters. Do I HAVE to use all that notation though? My particular class has a lot of fields as is, and uses a builder pattern too. Why can't I just stick with the original field variables rather than creating XProperty versions?

class ActionItem{
private String referenceNum;
private int percentComplete;
private ActionPlan actionPlans;
private LocalDate dateAssigned, dateDue, dateFinal, dateStarted,
     dateCompleted;
private String subject, description;
private Employee assignedBy, assignedToPrimary, assignedToSecondary;
private EmployeeGroup assignedToGroup;
private Criticality criticality;
private Status status;
----
private SimpleStringProperty referenceNumberProperty = new SimpleStringProperty();
private SimpleIntegerProperty percentCompleteProperty = new SimpleIntegerProperty();
private SimpleObjectProperty<ActionPlan> actionPlansProperty = new SimpleObjectProperty<ActionPlan>();
private SimpleObjectProperty<LocalDate> dateAssignedProperty = new SimpleObjectProperty<LocalDate>();
private SimpleObjectProperty<LocalDate> dateDueProperty = new SimpleObjectProperty<LocalDate>(),
     dateFinalProperty = new SimpleObjectProperty<LocalDate>(),
     dateStartedProperty = new SimpleObjectProperty<LocalDate>(),
     dateCompletedProperty = new SimpleObjectProperty<LocalDate>();
private SimpleStringProperty subjectProperty = new SimpleStringProperty(),
     descriptionProperty = new SimpleStringProperty();
private SimpleObjectProperty<Employee> assignedByProperty = new SimpleObjectProperty<Employee>(),
     assignedToPrimaryProperty = new SimpleObjectProperty<Employee>(),
     assignedToSecondaryProperty = new SimpleObjectProperty<Employee>();
private SimpleObjectProperty<EmployeeGroup> assignedToGroupProperty = new SimpleObjectProperty<EmployeeGroup>();
private SimpleObjectProperty<Criticality> criticalityProperty = new SimpleObjectProperty<ActionItem.Criticality>();
private SimpleObjectProperty<Status> statusProperty = new SimpleObjectProperty<ActionItem.Status>();
}

Does calling upon a getter method perform faster than trying to pull the object out of the SimpleProperty?

1
2
4/30/2014 2:36:30 AM

Accepted Answer

You can pretty much use any design you like.

The FX property pattern gives you a lot of functionality: it creates observable, writable, properties that in many cases can be wired directly into controls. So if you design your "table beans" using that pattern, then you can use the PropertyValueFactory as your cellValueFactory, and lots of stuff happens "automagically", such as updating table cells when the value changes, and vice-versa.

Using properties themselves doesn't add much overhead. There's a nice document that outlines some good practices for using FX properties.

The PropertyValueFactory, though, I think does add some overhead, as it relies on reflection to find the property from a specified name. So you will see some (I don't promise how much) benefit if you replace

myTableColumn.setCellValueFactory(new PropertyValueFactory<>("thing"));

with

myTableColumn.setCellValueFactory(new Callback<CellDataFeatures<S,T>, ObservableValue<T>>() {
    public ObservableValue<T> call(CellDataFeatures<S,T> data) {
        return data.getValue().thingProperty() ;
    }
});

(or, in Java 8, the much simpler

myTableColumn.setCellValueFactory(data -> data.getValue().thingProperty());

).

Now, if you don't need the bells and whistles of the JavaFX properties (for example, the values in the table row items won't be changed external to editing in the table, and the editing in the table needs to be "hard-wired" via a setOnCommit(...) anyway), then you can save the (small) overhead of the JavaFX properties by omitting them and just using the regular Javabean model, with getX() and setX(...) methods. There's some, though I think not much, performance benefit, and obviously less code.

The overhead from the reflection in the PropertyValueFactory is (my guess) larger than the overhead from using JavaFX properties, so if you're looking to do this for performance reasons, I would also explicitly wire the callback to the get method, instead of relying on the PropertyValueFactory. As in the link in @brian 's comment, some previous versions were highly inefficient in implementing that (though this is now fixed). So something like

class Item {
  private String name ;
  public String getName() {
    return name ;
  }
  public void setName(String name) {
    this.name = name ;
  }
}

TableColumn<Item, String> nameCol = new TableColumn<>("Name");
nameCol.setCellValueFactory(itemData -> new ReadOnlyStringWrapper(itemData.getValue.getName()));

is probably about as efficient as it gets: again though, if you want your table editable, you need to wire editing commits to calls to setName(...) by hand, and updates to the data external to the table won't be reflected in the table.

Bottom line: if you don't want to use JavaFX properties, you don't have to. You miss some free functionality, and there are ways to code that in yourself, and you might get some (slight) performance benefit as well as saving some code. The one case that's really hard to work around is updating properties displayed in the table, externally from table editing. If you are doing that in your code, JavaFX properties make your life a lot easier.

Update: Based on your comments, I would recommend using JavaFX properties for your use case. I strongly recommend reading the document linked above, slides 18-46, and especially the property patterns on slides 30-43.

In particular, though, use the abstract class (e.g. StringProperty) as the type for your property, not the concrete type (SimpleStringProperty), and when using properties as properties of objects, instantiate them with a name and reference to their bean. For example:

private StringProperty referenceNumberProperty = new SimpleStringProperty(this, "referenceNumber");
public final StringProperty referenceNumberProperty() {
    return referenceNumberProperty ;
}
public final String getReferenceNumber() {
    return referenceNumberProperty.get() ;
}
public final void setReferenceNumber(String referenceNumber) {
    this.referenceNumberProperty.set(referenceNumber);
}

Note that it's marginally more conventional not to include "property" as part of the reference name (i.e. private StringProperty referenceNumber instead of private StringProperty referenceNumberProperty), but of course that's totally up to you.

10
4/30/2014 12:47:57 PM

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