JDK-8244112 : Skin implementations: must not violate contract of dispose
  • Type: Bug
  • Component: javafx
  • Sub-Component: controls
  • Affected Version: openjfx14
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-04-29
  • Updated: 2020-08-25
  • Resolved: 2020-05-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
openjfx15Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
From dispose doc:

The methods getSkinnable() and getNode() should return null following a call to dispose. Calling dispose twice has no effect.

The last sentence in particular implies that the calling code need not worry about duplicate calls (either by the caller itself or any other), that is the following test must pass:

    @Test
    public void testSkinDispose() {
        showControl();
        control.getSkin().dispose();
        control.getSkin().dispose();
    }
    
It fails for some skins with an NPE, f.i. Tree/TableCell, Tree/TableView (there might be others, not yet tested). It's probably one of the reaons for JDK-8243940. Extracted this because the other issue might reveal additional quirks.


Comments
Changeset: bb243224 Author: Jeanette Winzenburg <fastegal@openjdk.org> Committer: Ajit Ghaisas <aghaisas@openjdk.org> Date: 2020-05-15 04:47:57 +0000 URL: https://git.openjdk.java.net/jfx/commit/bb243224
15-05-2020

To find all skins that don't guard themselves against a null skinnable, I added a cross-control (parameterized) test that calls dispose twice: when failing on second, it's this issue, when failing elsewhere (setup, showing, hiding ..) it's a different issue. Created separate issues for the second group: JDK-8244418 for MenuBarSkin (which blows on requestFocus if empty) JDK-8244419 for TextAreaSkin (which throws UnsupportedOperation instead of cleaning itself .. doooh) Started to add test support for "binch" testing of controls/skins to make it easier to test all against expected common (mis-)behavior like f.i. memory leaks on replacing/nulling skins.
05-05-2020

there are other misbehaving skins, found so far: - ButtonSkin, - MenuButtonSkin and SplitMenuButtonSkin (the offender is super), - TextAreaSkin (throws UnsupportedOperation .. that's not an option to cleanup),
30-04-2020

the technical reason resides in super's dispose: it tries to remove a listener to tableColumn's width property @Override public void dispose() { TableColumnBase<?,T> tableColumn = getTableColumn(); if (tableColumn != null) { tableColumn.widthProperty().removeListener(weakColumnWidthListener); } super.dispose(); } with getTableColumn delegating to an abstract property accessor that's implemented in subs: // base class /** * The TableColumnBase instance that is responsible for this Cell. * @return the TableColumnBase instance that is responsible for this Cell */ public abstract ReadOnlyObjectProperty<? extends TableColumnBase<S,T>> tableColumnProperty(); public final TableColumnBase<S,T> getTableColumn() { return tableColumnProperty().get(); } // concrete class /** {@inheritDoc} */ @Override public ReadOnlyObjectProperty<TableColumn<S,T>> tableColumnProperty() { return getSkinnable().tableColumnProperty(); } after the first dispose, the skinnable is nulled such that the second dispose blows. It's unusual that a property accessor throws a NPE: the usual expectation is that its safe to access, the returned property always != null while properties value might be null. Being public api, not much to do except enhancing the method doc in the base class ?
29-04-2020