public static Map<String, String> getEntries(final String json,
                                                 final Set<String> keys) {
        if (NullSafe.isBlankString(json) || !NullSafe.hasItems(keys)) {
            return Collections.emptyMap();
        } else {
            final Set<String> remainingFields = new HashSet<>(keys);
            final Map<String, String> results = new HashMap<>();

            final JsonFactory jFactory = new JsonFactory();
            JsonParser jParser = null;
            JsonToken jsonToken;
            JsonToken startRootToken = null;
            JsonToken endRootToken = null;
            try {
                jParser = jFactory.createParser(json);
                while (true) {
                    jsonToken = jParser.nextToken();
                    LOGGER.trace("jsonToken: {}", jsonToken);

                    if (jsonToken == null
                        || (startRootToken == null && !(jsonToken == JsonToken.START_OBJECT))
                        || jsonToken == endRootToken
                        || remainingFields.isEmpty()) {
                        break;
                    }

                    if (jsonToken == JsonToken.FIELD_NAME) {
                        final String fieldName = jParser.getCurrentName();
                        if (remainingFields.contains(fieldName)) {
                            String value = jParser.nextTextValue();
                            if (value != null) {
                                results.put(fieldName, value);
                                remainingFields.remove(fieldName);
                            }
                        }
                    } else if (jsonToken == JsonToken.START_OBJECT && startRootToken != null) {
                        // Skip over this complex sub-object
                        while (jsonToken != JsonToken.END_OBJECT) {
                            jsonToken = jParser.nextToken();
                        }
                    } else if (jsonToken == JsonToken.START_ARRAY) {
                        // Skip over this array
                        while (jsonToken != JsonToken.END_ARRAY) {
                            jsonToken = jParser.nextToken();
                        }
                    }

                    if (startRootToken == null) {
                        startRootToken = jsonToken;
                        endRootToken = JsonToken.END_OBJECT;
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException(LogUtil.message(
                        "Error extracting fields '{}' from json:\n{}", keys, json));
            } finally {
                NullSafe.consume(jParser, ThrowingConsumer.unchecked(JsonParser::close));
            }
            return results;
        }
    }
Gets the entries from the passed json that are children of the root object.
Avoids having to parse the whole object if you only want to get a few keys.
Does not descend into child objects/arrays.
If the root is an array, returns an empty map.

@param json The json to parse.
@param keys The fields to find.
@return The entries with keys matching keys
stroom-util/src/main/java/stroom/util/json/JsonUtil.java