Hi Ben,
Thank you. That does indeed reproduce the problem for me on the 100th
iteration. I've attached your test program to the bug report.
-- Kevin
On 2/13/2020 11:22 PM, Peter, Benjamin wrote:
Hello Kevin,
sure, will do :-).
==== BEGIN ====
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
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.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
public class TableViewCellDisposeProblem extends Application {
public static class Person {
private StringProperty firstName;
public void setFirstName(String value) {
firstNameProperty().set(value);
}
public String getFirstName() {
return firstNameProperty().get();
}
public StringProperty firstNameProperty() {
if (firstName == null)
firstName = new SimpleStringProperty(this, "firstName");
return firstName;
}
private StringProperty lastName;
public void setLastName(String value) {
lastNameProperty().set(value);
}
public String getLastName() {
return lastNameProperty().get();
}
public StringProperty lastNameProperty() {
if (lastName == null)
lastName = new SimpleStringProperty(this, "lastName");
return lastName;
}
public Person(String firstName, String lastName) {
setFirstName(firstName);
setLastName(lastName);
}
}
private ObservableList<Person> teamMembers =
FXCollections.observableArrayList( //
List.of( //
new Person("William", "Reed"), //
new Person("James", "Michaelson"), //
new Person("Julius", "Dean") //
));
TableView<Person> table = new TableView<>();
private AtomicInteger updateCount = new AtomicInteger();
public void updateLoop() {
Thread thread = new Thread(() -> {
while (true) {
System.out.println("updating i = "+
updateCount.incrementAndGet());
Platform.runLater(() -> {
// Trigger column visibility - Without this, no exception
observed!
TableColumn<Person, ?> secondColumn =
table.getColumns().get(1);
secondColumn.setVisible(!secondColumn.isVisible());
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("interrupted");
break;
}
}
});
thread.setDaemon(true);
thread.start();
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(table, 800, 600));
table.setItems(teamMembers);
TableColumn<Person, String> firstNameCol = new TableColumn<>("First
Name");
firstNameCol.setCellValueFactory(new
PropertyValueFactory<>("firstName"));
TableColumn<Person, String> lastNameCol = new TableColumn<>("Last
Name");
lastNameCol.setCellValueFactory(new
PropertyValueFactory<>("lastName"));
table.getColumns().setAll(firstNameCol, lastNameCol);
primaryStage.show();
updateLoop();
}
public static void main(String[] args) {
Application.launch(args);
}
}
/*
* After 100 updates following Exception occurs (of 5 test runs, sleep time
varied):
*
* [WARNING]
java.lang.NullPointerException
at javafx.scene.control.skin.TableCellSkin.tableColumnProperty
(TableCellSkin.java:97)
at javafx.scene.control.skin.TableCellSkinBase.getTableColumn
(TableCellSkinBase.java:123)
at javafx.scene.control.skin.TableCellSkinBase.dispose
(TableCellSkinBase.java:136)
at javafx.scene.control.skin.TableCellSkin.dispose (TableCellSkin.java:88)
at javafx.scene.control.Control$2.invalidated (Control.java:267)
at javafx.beans.property.ObjectPropertyBase.markInvalid
(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set
(ObjectPropertyBase.java:147)
at javafx.css.StyleableObjectProperty.set (StyleableObjectProperty.java:82)
at javafx.scene.control.Control$2.set (Control.java:250)
at javafx.scene.control.Control$2.set (Control.java:233)
at javafx.scene.control.Control.setSkin (Control.java:230)
at javafx.scene.control.skin.TableRowSkinBase.recreateCells
(TableRowSkinBase.java:715)
at javafx.scene.control.skin.TableRowSkinBase.updateCells
(TableRowSkinBase.java:505)
at javafx.scene.control.skin.TableRowSkinBase.checkState
(TableRowSkinBase.java:649)
at javafx.scene.control.skin.TableRowSkinBase.computePrefHeight
(TableRowSkinBase.java:588)
at javafx.scene.control.Control.computePrefHeight (Control.java:570)
at javafx.scene.Parent.prefHeight (Parent.java:1039)
at javafx.scene.layout.Region.prefHeight (Region.java:1559)
at javafx.scene.control.skin.VirtualFlow.resizeCell (VirtualFlow.java:1923)
at javafx.scene.control.skin.VirtualFlow.addLeadingCells
(VirtualFlow.java:2030)
at javafx.scene.control.skin.VirtualFlow.layoutChildren
(VirtualFlow.java:1250)
at javafx.scene.Parent.layout (Parent.java:1206)
at javafx.scene.Parent.layout (Parent.java:1213)
at javafx.scene.Scene.doLayoutPass (Scene.java:576)
at javafx.scene.Scene$ScenePulseListener.pulse (Scene.java:2482)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$2 (Toolkit.java:412)
at java.security.AccessController.doPrivileged (Native Method)
at com.sun.javafx.tk.Toolkit.runPulse (Toolkit.java:411)
at com.sun.javafx.tk.Toolkit.firePulse (Toolkit.java:438)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse (QuantumToolkit.java:563)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse (QuantumToolkit.java:543)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue
(QuantumToolkit.java:536)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11
(QuantumToolkit.java:342)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run
(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.gtk.GtkApplication._runLoop (Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11
(GtkApplication.java:277)
at java.lang.Thread.run (Thread.java:834)
updating
[WARNING]
java.lang.NullPointerException
at javafx.scene.control.skin.CellSkinBase$StyleableProperties$1.isSettable
(CellSkinBase.java:166)
at javafx.scene.control.skin.CellSkinBase$StyleableProperties$1.isSettable
(CellSkinBase.java:161)
at javafx.scene.CssStyleHelper.transitionToState (CssStyleHelper.java:666)
at javafx.scene.Node.doProcessCSS (Node.java:9658)
at javafx.scene.Node$1.doProcessCSS (Node.java:471)
at com.sun.javafx.scene.NodeHelper.processCSSImpl (NodeHelper.java:192)
at com.sun.javafx.scene.ParentHelper.superProcessCSSImpl
(ParentHelper.java:93)
at com.sun.javafx.scene.ParentHelper.superProcessCSS (ParentHelper.java:63)
at javafx.scene.Parent.doProcessCSS (Parent.java:1368)
at javafx.scene.Parent$1.doProcessCSS (Parent.java:125)
at com.sun.javafx.scene.ParentHelper.processCSSImpl (ParentHelper.java:98)
at com.sun.javafx.scene.control.ControlHelper.superProcessCSSImpl
(ControlHelper.java:63)
at com.sun.javafx.scene.control.ControlHelper.superProcessCSS
(ControlHelper.java:55)
at javafx.scene.control.Control.doProcessCSS (Control.java:886)
at javafx.scene.control.Control$1.doProcessCSS (Control.java:89)
at com.sun.javafx.scene.control.ControlHelper.processCSSImpl
(ControlHelper.java:67)
at com.sun.javafx.scene.NodeHelper.processCSS (NodeHelper.java:145)
at javafx.scene.Node.processCSS (Node.java:9540)
at javafx.scene.Node.processCSS (Node.java:9533)
at javafx.scene.Node.processCSS (Node.java:9533)
at javafx.scene.Node.processCSS (Node.java:9533)
at javafx.scene.Node.processCSS (Node.java:9533)
at javafx.scene.Node.processCSS (Node.java:9533)
at javafx.scene.Scene.doCSSPass (Scene.java:569)
at javafx.scene.Scene$ScenePulseListener.pulse (Scene.java:2477)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$2 (Toolkit.java:412)
at java.security.AccessController.doPrivileged (Native Method)
at com.sun.javafx.tk.Toolkit.runPulse (Toolkit.java:411)
at com.sun.javafx.tk.Toolkit.firePulse (Toolkit.java:438)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse (QuantumToolkit.java:563)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse (QuantumToolkit.java:543)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue
(QuantumToolkit.java:536)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11
(QuantumToolkit.java:342)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run
(InvokeLaterDispatcher.java:96)
at com.sun.glass.ui.gtk.GtkApplication._runLoop (Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11
(GtkApplication.java:277)
at java.lang.Thread.run (Thread.java:834)
updating
*/
===== END ====
best wishes,
Ben
-----Ursprüngliche Nachricht-----
Von: Kevin Rushforth <[email protected]>
Gesendet: Donnerstag, 13. Februar 2020 15:46
An: Peter, Benjamin <[email protected]>; [email protected]
Betreff: Re: WG: Minimal reproduction example for JDK-8217953 NPE in
TableCellSkin
Unfortunately, attachments don't make it through the openjdk mailing list
filters.
Can you just paste it inline?
Thanks.
-- Kevin
On 2/13/2020 6:02 AM, Peter, Benjamin wrote:
Hello devs,
same example but with the file as attachment and without header.
regards,
Ben
-----Ursprüngliche Nachricht-----
Von: openjfx-dev <[email protected]> Im Auftrag von
Peter, Benjamin
Gesendet: Donnerstag, 13. Februar 2020 11:54
An: [email protected]
Betreff: Minimal reproduction example for JDK-8217953 NPE in
TableCellSkin
Dear FX devs,
please accept my minimal reproduction example for JDK-8217953
"NullPointerException when TableCellSkin gets disposed twice"
In the report it says there was no luck reproducing it - I hope this could now
be
beneficial for a solution to this problem.
I could repeatedly trigger the problem after 100 of my update cycles - which
interestingly corresponds to the following constant which can be found along the
stacktrace.
javafx.scene.control.skin.TableRowSkinBase.DEFAULT_FULL_REFRESH_COUNTER
= 100 Surely - could be coincidence - but also a hot lead.
I can also confirm it is still reproducable in jfx 11 and 13.
It is available as public domain gist on github:
https://gist.github.com/dedeibel/d02fb51c59942bebcb6e418f23d310fb
Thank you for your work and cooperation,
with kind regards,
Benjamin Peter