private void doGetCombinedWordList(final DocRefDecorator docRefDecorator,
                                       final WordList.Builder wordListBuilder,
                                       final DocRef docRef,
                                       final Set<DocRef> visited,
                                       final Stack<DocRef> visitPath) {

        // As we are adding the docRef to the WordList, we want to ensure it
        // has a name and the correct name
        final DocRef decorateDocRef = decorateDocRef(docRefDecorator, docRef);
        LOGGER.debug(() -> LogUtil.message("decorateDocRef: {}, visitPath: {}",
                decorateDocRef.toShortString(), docRefsToStr(visitPath)));
        visitPath.push(decorateDocRef);

        // Prevent circular import dependencies.
        if (!visited.contains(decorateDocRef)) {
            visited.add(decorateDocRef);

            try {
                // If deDup is true then the lowest level dict will win, or
                // if duplicates appear in multiple sibling imports then the first
                // sibling encountered with it will win.
                // This is to be consistent with existing behaviour where imports come first
                // in the combined word list.
                // Precedence only impacts the source inside the Word object.
                final DictionaryDoc doc = readDocument(decorateDocRef);
                if (doc != null) {
                    // First add the words from each of the imports (and recursing into their imports too)
                    final List<DocRef> imports = doc.getImports();
                    if (NullSafe.hasItems(imports)) {
                        LOGGER.debug(() -> LogUtil.message("docRef: {} has imports: {}",
                                decorateDocRef.toShortString(), docRefsToStr(imports)));

                        for (final DocRef importDocRef : imports) {
                            // Recurse
                            doGetCombinedWordList(
                                    docRefDecorator,
                                    wordListBuilder,
                                    importDocRef,
                                    visited,
                                    visitPath);
                        }
                    }

                    // Add the words from this dict first as the higher level takes precedence
                    final String data = doc.getData();
                    if (NullSafe.isNonBlankString(data)) {
                        StringUtil.splitToLines(data, true)
                                .forEach(line ->
                                        wordListBuilder.addWord(line, decorateDocRef));
                    }
                }
            } catch (final PermissionException e) {
                // Silently ignore permission exceptions as not all users will be able to read all dicts
                LOGGER.debug(() -> LogUtil.message("Permission exception reading {}: {}",
                        decorateDocRef, e.getMessage()), e);
            }
        } else {
            LOGGER.debug(() -> LogUtil.message("Found circular import, ignoring {}, visitPath: {}",
                    decorateDocRef.toShortString(), docRefsToStr(visitPath)));
        }

        visitPath.pop();
    }
//     * Ensure all the imports have the correct names. Modifies the import list.
//
stroom-dictionary/stroom-dictionary-impl/src/main/java/stroom/dictionary/impl/DictionaryStoreImpl.java