@Override public boolean hasPath(String pathExpression) { Path path = Path.newPath(pathExpression); ConfigValue peeked; try { peeked = object.peekPath(path); } catch (ConfigException.NotResolved e) { throw ConfigImpl.improveNotResolved(path, e); } return peeked != null && peeked.valueType() != ConfigValueType.NULL; }
private static AbstractConfigValue find( AbstractConfigObject self, Path path, ConfigValueType expected, Path originalPath) { try { String key = path.first(); Path next = path.remainder(); if (next == null) { return findKey(self, key, expected, originalPath); } else { AbstractConfigObject o = (AbstractConfigObject) findKey( self, key, ConfigValueType.OBJECT, originalPath.subPath(0, originalPath.length() - next.length())); assert (o != null); // missing was supposed to throw return find(o, next, expected, originalPath); } } catch (ConfigException.NotResolved e) { throw ConfigImpl.improveNotResolved(path, e); } }
private static AbstractConfigObject fromPathMap( ConfigOrigin origin, Map<Path, Object> pathMap, boolean convertedFromProperties) { /* * First, build a list of paths that will have values, either string or * object values. */ Set<Path> scopePaths = new HashSet<Path>(); Set<Path> valuePaths = new HashSet<Path>(); for (Path path : pathMap.keySet()) { // add value's path valuePaths.add(path); // all parent paths are objects Path next = path.parent(); while (next != null) { scopePaths.add(next); next = next.parent(); } } if (convertedFromProperties) { /* * If any string values are also objects containing other values, * drop those string values - objects "win". */ valuePaths.removeAll(scopePaths); } else { /* If we didn't start out as properties, then this is an error. */ for (Path path : valuePaths) { if (scopePaths.contains(path)) { throw new ConfigException.BugOrBroken( "In the map, path '" + path.render() + "' occurs as both the parent object of a value and as a value. " + "Because Map has no defined ordering, this is a broken situation."); } } } /* * Create maps for the object-valued values. */ Map<String, AbstractConfigValue> root = new HashMap<String, AbstractConfigValue>(); Map<Path, Map<String, AbstractConfigValue>> scopes = new HashMap<Path, Map<String, AbstractConfigValue>>(); for (Path path : scopePaths) { Map<String, AbstractConfigValue> scope = new HashMap<String, AbstractConfigValue>(); scopes.put(path, scope); } /* Store string values in the associated scope maps */ for (Path path : valuePaths) { Path parentPath = path.parent(); Map<String, AbstractConfigValue> parent = parentPath != null ? scopes.get(parentPath) : root; String last = path.last(); Object rawValue = pathMap.get(path); AbstractConfigValue value; if (convertedFromProperties) { value = new ConfigString(origin, (String) rawValue); } else { value = ConfigImpl.fromAnyRef(pathMap.get(path), origin, FromMapMode.KEYS_ARE_PATHS); } parent.put(last, value); } /* * Make a list of scope paths from longest to shortest, so children go * before parents. */ List<Path> sortedScopePaths = new ArrayList<Path>(); sortedScopePaths.addAll(scopePaths); // sort descending by length Collections.sort( sortedScopePaths, new Comparator<Path>() { @Override public int compare(Path a, Path b) { // Path.length() is O(n) so in theory this sucks // but in practice we can make Path precompute length // if it ever matters. return b.length() - a.length(); } }); /* * Create ConfigObject for each scope map, working from children to * parents to avoid modifying any already-created ConfigObject. This is * where we need the sorted list. */ for (Path scopePath : sortedScopePaths) { Map<String, AbstractConfigValue> scope = scopes.get(scopePath); Path parentPath = scopePath.parent(); Map<String, AbstractConfigValue> parent = parentPath != null ? scopes.get(parentPath) : root; AbstractConfigObject o = new SimpleConfigObject( origin, scope, ResolveStatus.RESOLVED, false /* ignoresFallbacks */); parent.put(scopePath.last(), o); } // return root config object return new SimpleConfigObject( origin, root, ResolveStatus.RESOLVED, false /* ignoresFallbacks */); }