В вашем Bill
классе у вас есть:
public class Bill {
private String project;
// getter
public String getProject() {
return project;
}
// setter
public void setProject(String project) {
this.project = project;
}
// ????
public String projectProperty() {
return project;
}
}
Когда вы используете обратный вызов new PropertyValueFactory("project")
для фабрики значений ячеек TableColumn, это происходит при оценке метода call
:
@Override
public ObservableValue<T> call(CellDataFeatures<S,T> param) {
return getCellDataReflectively(param.getValue());
}
private ObservableValue<T> getCellDataReflectively(S rowData) {
...
if (propertyRef.hasProperty()) {
return propertyRef.getProperty(rowData);
} else {
T value = propertyRef.get(rowData);
return new ReadOnlyObjectWrapper<T>(value);
}
...
}
В первую очередь предпринимается попытка использовать свойство JavaFX, где в PropertyReference
вы можете увидеть:
public boolean hasProperty() {
reflect();
return propertyGetter != null;
}
Поскольку вы предоставляете метод projectProperty()
, этот метод ошибочно принимается за propertyGetter
, поскольку он заканчивается на Property
в reflect()
:
// Now attempt to look for the property-getter.
final String propertyGetterName = name + "Property";
, поэтому он вернет true, а затем getProperty()
попытается привести это свойство:
try {
return (ReadOnlyProperty<T>)MethodHelper.invoke(propertyGetter, bean, (Object[])null);
}
и это вызовет исключение, которое вы получите:
Caused by: java.lang.ClassCastException: class java.lang.String cannot be cast to class javafx.beans.property.ReadOnlyProperty (java.lang.String is in module java.base of loader 'bootstrap'; javafx.beans.property.ReadOnlyProperty is in module javafx.base of loader 'app')
at javafx.base/com.sun.javafx.property.PropertyReference.getProperty(PropertyReference.java:197)
, поскольку ваш String project
не может быть явно приведен к ReadOnlyProperty
.
Решение
Вы либо используете правильное свойство:
private final StringProperty project = new SimpleStringProperty();
public final StringProperty projectProperty() {
return project;
}
public final String getProject() {
return project.get();
}
public final void setProject(String value) {
project.set(value);
}
Или вы удаляете неправильное средство получения свойства, и тогда обратный вызов по умолчанию будет использоваться во втором случае с использованием примитива String в getCellDataReflectively
, который будет преобразован в свойство только для чтения:
T value = propertyRef.get(rowData);
return new ReadOnlyObjectWrapper<T>(value);
Хотя это работает нормально, предпочтительнее первый вариант, использующий надлежащие свойства JavaFX.