-
Bug
-
Resolution: Not an Issue
-
P1
-
None
-
8u20
-
Windows 7 x64. All current latest patches.
*** EXACT ISSUE VERSION ***
JDK 8, 8u20 b19
*** IMPORTANT ***
This worked on 8u05, must've appeared in 8u20 b19, possibly between b10+ and b19 as I don't recall seeing it before and I've stayed up to date on betas.
*** ISSUE ***
If you have a table updated from an observable list that keeps getting items appended to it from a background task/service, this works as expected and the table updates. BUT if you start adding those items at position 0 in the observable list, you get immediate exceptions saying:
java.lang.IllegalStateException: Not on FX application thread
*** CODE TO REPRODUCE ***
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
* Problem class showing that updating an observable list at position 0 causes IllegalStateExceptions
*/
public class ObservableListProblem extends Application {
@Override
public void start(Stage stage) throws Exception {
final BorderPane wrapper = new BorderPane();
TableView<OneRow> table = new TableView<OneRow>();
table.getSelectionModel().setCellSelectionEnabled(false);
table.setEditable(false);
final ObservableList<OneRow> tableData = FXCollections.observableArrayList();
TableColumn<OneRow, String> col1 = new TableColumn<OneRow, String>("First Name");
col1.setCellValueFactory(new PropertyValueFactory<OneRow, String>("firstName"));
TableColumn<OneRow, String> col2 = new TableColumn<OneRow, String>("Last Name");
col2.setCellValueFactory(new PropertyValueFactory<OneRow, String>("lastName"));
table.setItems(tableData);
table.getColumns().add(col1);
table.getColumns().add(col2);
wrapper.setCenter(table);
Scene mainScene = new Scene(wrapper, 800, 600);
stage.setScene(mainScene);
Task<Void> updateTask = new Task<Void>() {
@Override
protected Void call() throws Exception {
while (true) {
// CODE THAT WORKS
//tableData.add(new OneRow("xxx", "yyyy"));
// CODE THAT MAKES IT BLOW UP
tableData.add(0, new OneRow("xxx", "yyyy"));
Thread.sleep(1000);
}
}
};
new Thread(updateTask).start();
stage.show();
stage.setOnCloseRequest(e -> {
Platform.exit();
System.exit(0);
});
}
public static void main(String [] args) {
launch(args);
}
public class OneRow {
public OneRow(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
private StringProperty _firstNameProperty;
private StringProperty _lastNameProperty;
public StringProperty firstNameProperty() {
if (_firstNameProperty == null) {
_firstNameProperty = new SimpleStringProperty();
}
return _firstNameProperty;
}
public void setFirstName(String firstName) {
firstNameProperty().set(firstName);
}
public String getFirstName() {
return firstNameProperty().get();
}
public StringProperty lastNameProperty() {
if (_lastNameProperty == null) {
_lastNameProperty = new SimpleStringProperty();
}
return _lastNameProperty;
}
public void setLastName(String lastName) {
lastNameProperty().set(lastName);
}
public String getLastName() {
return lastNameProperty().get();
}
}
}
*** FULL EXCEPTION ***
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.Node.notifyParentsOfInvalidatedCSS(Node.java:8709)
at javafx.scene.Node.requestCssStateTransition(Node.java:8639)
at javafx.scene.Node.pseudoClassStateChanged(Node.java:8680)
at javafx.scene.control.Cell$3.invalidated(Cell.java:456)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.scene.control.Cell.setSelected(Cell.java:476)
at javafx.scene.control.Cell.updateSelected(Cell.java:684)
at javafx.scene.control.TableRow.updateSelection(TableRow.java:291)
at javafx.scene.control.TableRow.lambda$new$57(TableRow.java:101)
at javafx.scene.control.TableRow$$Lambda$193/377640639.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TableView.java:2880)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.lambda$new$47(TableView.java:1984)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel$$Lambda$79/1484689336.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
at javafx.collections.transformation.TransformationList.lambda$getListener$16(TransformationList.java:106)
at javafx.collections.transformation.TransformationList$$Lambda$81/1149516160.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
at com.sun.javafx.scene.control.SelectedCellsMap.clear(SelectedCellsMap.java:183)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2561)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.updateSelection(TableView.java:2185)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.access$2300(TableView.java:1959)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:2057)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:50)
at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:1)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1409)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
JDK 8, 8u20 b19
*** IMPORTANT ***
This worked on 8u05, must've appeared in 8u20 b19, possibly between b10+ and b19 as I don't recall seeing it before and I've stayed up to date on betas.
*** ISSUE ***
If you have a table updated from an observable list that keeps getting items appended to it from a background task/service, this works as expected and the table updates. BUT if you start adding those items at position 0 in the observable list, you get immediate exceptions saying:
java.lang.IllegalStateException: Not on FX application thread
*** CODE TO REPRODUCE ***
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
/**
* Problem class showing that updating an observable list at position 0 causes IllegalStateExceptions
*/
public class ObservableListProblem extends Application {
@Override
public void start(Stage stage) throws Exception {
final BorderPane wrapper = new BorderPane();
TableView<OneRow> table = new TableView<OneRow>();
table.getSelectionModel().setCellSelectionEnabled(false);
table.setEditable(false);
final ObservableList<OneRow> tableData = FXCollections.observableArrayList();
TableColumn<OneRow, String> col1 = new TableColumn<OneRow, String>("First Name");
col1.setCellValueFactory(new PropertyValueFactory<OneRow, String>("firstName"));
TableColumn<OneRow, String> col2 = new TableColumn<OneRow, String>("Last Name");
col2.setCellValueFactory(new PropertyValueFactory<OneRow, String>("lastName"));
table.setItems(tableData);
table.getColumns().add(col1);
table.getColumns().add(col2);
wrapper.setCenter(table);
Scene mainScene = new Scene(wrapper, 800, 600);
stage.setScene(mainScene);
Task<Void> updateTask = new Task<Void>() {
@Override
protected Void call() throws Exception {
while (true) {
// CODE THAT WORKS
//tableData.add(new OneRow("xxx", "yyyy"));
// CODE THAT MAKES IT BLOW UP
tableData.add(0, new OneRow("xxx", "yyyy"));
Thread.sleep(1000);
}
}
};
new Thread(updateTask).start();
stage.show();
stage.setOnCloseRequest(e -> {
Platform.exit();
System.exit(0);
});
}
public static void main(String [] args) {
launch(args);
}
public class OneRow {
public OneRow(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
private StringProperty _firstNameProperty;
private StringProperty _lastNameProperty;
public StringProperty firstNameProperty() {
if (_firstNameProperty == null) {
_firstNameProperty = new SimpleStringProperty();
}
return _firstNameProperty;
}
public void setFirstName(String firstName) {
firstNameProperty().set(firstName);
}
public String getFirstName() {
return firstNameProperty().get();
}
public StringProperty lastNameProperty() {
if (_lastNameProperty == null) {
_lastNameProperty = new SimpleStringProperty();
}
return _lastNameProperty;
}
public void setLastName(String lastName) {
lastNameProperty().set(lastName);
}
public String getLastName() {
return lastNameProperty().get();
}
}
}
*** FULL EXCEPTION ***
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.Node.notifyParentsOfInvalidatedCSS(Node.java:8709)
at javafx.scene.Node.requestCssStateTransition(Node.java:8639)
at javafx.scene.Node.pseudoClassStateChanged(Node.java:8680)
at javafx.scene.control.Cell$3.invalidated(Cell.java:456)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:143)
at javafx.scene.control.Cell.setSelected(Cell.java:476)
at javafx.scene.control.Cell.updateSelected(Cell.java:684)
at javafx.scene.control.TableRow.updateSelection(TableRow.java:291)
at javafx.scene.control.TableRow.lambda$new$57(TableRow.java:101)
at javafx.scene.control.TableRow$$Lambda$193/377640639.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList.callObservers(ReadOnlyUnbackedObservableList.java:75)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.handleSelectedCellsListChangeEvent(TableView.java:2880)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.lambda$new$47(TableView.java:1984)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel$$Lambda$79/1484689336.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.transformation.SortedList.sourceChanged(SortedList.java:108)
at javafx.collections.transformation.TransformationList.lambda$getListener$16(TransformationList.java:106)
at javafx.collections.transformation.TransformationList$$Lambda$81/1149516160.onChanged(Unknown Source)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
at com.sun.javafx.scene.control.SelectedCellsMap.clear(SelectedCellsMap.java:183)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.quietClearSelection(TableView.java:2561)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.updateSelection(TableView.java:2185)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.access$2300(TableView.java:1959)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:2057)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:50)
at com.bugtest.ObservableListProblem$1.call(ObservableListProblem.java:1)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1409)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)