From: Tuukka Lehtonen Date: Thu, 11 Oct 2018 13:15:15 +0000 (+0300) Subject: Fixed NPE problems from ParentNode by reintroducing child map sentinels X-Git-Tag: v1.43.0~136^2~332 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=1e2054286ceb10165f941ed7f57b60892cf86a6a Fixed NPE problems from ParentNode by reintroducing child map sentinels gitlab #65 Change-Id: I63778c368f197a4b92e71c96a37fd569ad7cb51c --- diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/ParentNode.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/ParentNode.java index e9e0b4be3..976857afe 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/ParentNode.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/ParentNode.java @@ -14,9 +14,11 @@ package org.simantics.scenegraph; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import gnu.trove.map.TLongObjectMap; import gnu.trove.map.hash.TLongObjectHashMap; /** @@ -46,8 +48,41 @@ public abstract class ParentNode extends Node { } }; - protected transient Map children = createChildMap(); - private transient TLongObjectHashMap childrenIdMap = new TLongObjectHashMap<>(); + private static class ImmutableIdMap extends TLongObjectHashMap { + private static final String MSG = "immutable singleton instance"; + + @Override + public String put(long key, String value) { + throw new UnsupportedOperationException(MSG); + } + @Override + public void putAll(Map map) { + throw new UnsupportedOperationException(MSG); + } + @Override + public void putAll(TLongObjectMap map) { + throw new UnsupportedOperationException(MSG); + } + @Override + public String putIfAbsent(long key, String value) { + throw new UnsupportedOperationException(MSG); + } + } + + /** + * This is the value given to {@link #children} when this node is disposed and + * cleaned up. + */ + private static final Map DISPOSED_CHILDREN = Collections.emptyMap(); + + /** + * This is the value given to {@link #childrenIdMap} when this node is disposed + * and cleaned up. + */ + private static final TLongObjectMap DISPOSED_CHILDREN_ID_MAP = new ImmutableIdMap(); + + protected transient Map children = createChildMap(); + private transient TLongObjectMap childrenIdMap = new TLongObjectHashMap<>(); /** * A cached value for the root node of this parent node. This makes it @@ -232,15 +267,15 @@ public abstract class ParentNode extends Node { @Override public void cleanup() { retractMapping(); - if (children != null) { + if (children != DISPOSED_CHILDREN) { children.forEach((id, child) -> { child.cleanup(); child.setParent(null); }); children.clear(); childrenIdMap.clear(); - children = null; - childrenIdMap = null; + children = DISPOSED_CHILDREN; + childrenIdMap = DISPOSED_CHILDREN_ID_MAP; childrenChanged(); rootNodeCache = DISPOSED; }