AW: WG: Minimal reproduction example for JDK-8217953 NPE in TableCellSkin
Kevin Rushforth
kevin.rushforth at oracle.com
Fri Feb 14 13:17:49 UTC 2020
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 <kevin.rushforth at oracle.com>
>> Gesendet: Donnerstag, 13. Februar 2020 15:46
>> An: Peter, Benjamin <B.Peter at gsi.de>; openjfx-dev at openjdk.java.net
>> 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 <openjfx-dev-bounces at openjdk.java.net> Im Auftrag von
>>> Peter, Benjamin
>>> Gesendet: Donnerstag, 13. Februar 2020 11:54
>>> An: openjfx-dev at openjdk.java.net
>>> 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
More information about the openjfx-dev
mailing list