private ExplorerNode decorate(final K nodeKey,
                                  final ExplorerNode node,
                                  final BiFunction<K, ExplorerNode, ExplorerNode> nodeDecorator) {
        Objects.requireNonNull(node);

        final Set<ExplorerNode> childNodes = parentKeyToChildNodesMap.get(nodeKey);
        boolean hasAnyNodeChanged = false;
        final Set<ExplorerNode> newChildNodes = NullSafe.getOrElseGet(
                childNodes,
                childNodes2 -> new LinkedHashSet<>(childNodes2.size()),
                Collections::emptySet);

        if (NullSafe.hasItems(childNodes)) {
            // Branch, so recurse into each to decorate it
            for (final ExplorerNode childNode : childNodes) {
                if (childNode != null) {
                    final K childNodeKey = getNodeKey(childNode);
                    final ExplorerNode newChildNode = decorate(childNodeKey, childNode, nodeDecorator);
                    if (newChildNode != childNode) {
                        hasAnyNodeChanged = true;
                        keyToNodeMap.put(childNodeKey, newChildNode);
                    }
                    newChildNodes.add(newChildNode);
                } else {
                    // Not sure we want this else block
                    newChildNodes.add(null);
                    keyToNodeMap.put(null, null);
                }
            }
            if (hasAnyNodeChanged) {
                parentKeyToChildNodesMap.put(nodeKey, newChildNodes);
            }
        }

        // Decorate this node
        final ExplorerNode newNode = nodeDecorator.apply(nodeKey, node);
        if (newNode != node) {
            hasAnyNodeChanged = true;
            keyToNodeMap.put(nodeKey, newNode);
        }

        if (hasAnyNodeChanged) {
            // Now link the new children (if any) to the new node (their parent)
            for (final ExplorerNode newChildNode : newChildNodes) {
                final K newChildNodeKey = getNodeKey(newChildNode);
                childKeyToParentNodeMap.put(newChildNodeKey, newNode);
            }
        }

        return newNode;
    }
@param nodeDecorator Returns a decorated copy of the node passed to it. It MUST have the
                     same node key as the node passed in. Will be called for each node in
                     a depth first way, with siblings processed in no specific order.
stroom-explorer/stroom-explorer-impl/src/main/java/stroom/explorer/impl/AbstractTreeModel.java