Skip to content

Instantly share code, notes, and snippets.

@dedeibel
Created February 13, 2020 10:46
Show Gist options
  • Save dedeibel/370f5f3558b66f74c2f4137be363a7ca to your computer and use it in GitHub Desktop.
Save dedeibel/370f5f3558b66f74c2f4137be363a7ca to your computer and use it in GitHub Desktop.
Minimal reproduction example for JDK-8217953 NPE in TableCellSkin
/*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <https://unlicense.org>
*/
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
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment