From 1e2054286ceb10165f941ed7f57b60892cf86a6a Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Thu, 11 Oct 2018 16:15:15 +0300 Subject: [PATCH 1/1] Fixed NPE problems from ParentNode by reintroducing child map sentinels gitlab #65 Change-Id: I63778c368f197a4b92e71c96a37fd569ad7cb51c --- .../org/simantics/scenegraph/ParentNode.java | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) 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; } -- 2.43.2