![JAR search and dependency download from the Maven repository](/logo.png)
yakworks.commons.map.LazyPathKeyMap.groovy Maven / Gradle / Ivy
/*
* Copyright 2023 original authors
* SPDX-License-Identifier: Apache-2.0
*/
package yakworks.commons.map
import groovy.transform.CompileStatic
/**
* based on org.apache.groovy.json.internal.LazyMap
*/
@CompileStatic
public class LazyPathKeyMap extends AbstractMap {
/** the delimiter, defaults to '.' can be changed to somthing like _ so would break apart fields like foo_bar*/
String pathDelimiter = '.'
/** defaults to false, whether to remove the orginal path key after its been nested into maps */
boolean removePathKeys = true
/** TODO (MAKE THIS WORK) When set to false will keep the Map flat */
boolean enabled = true
/* Holds the actual backing map that will be lazily created. */
protected Map map;
/* Holds the source map with the path keys */
private Map sourceMap;
private boolean initialized = false
/**
* Populates the PathKeyMap with supplied map.
*
* @param values The values to populate with
*/
LazyPathKeyMap(Map sourceMap) {
this.sourceMap = sourceMap ?: ([:] as Map)
}
static LazyPathKeyMap of(Map sourceMap, String pathDelimiter = '.' ){
def pkm = new LazyPathKeyMap(sourceMap)
pkm.pathDelimiter = pathDelimiter
return pkm
}
LazyPathKeyMap pathDelimiter(String v){
this.pathDelimiter = v
return this
}
/** sets the backing map that backs this map, this would rarely be used, clone would be an example */
LazyPathKeyMap map(String v){
this.pathDelimiter = v
return this
}
public Map getSourceMap(){
return this.sourceMap
}
/** used to make tests easier and to do asserts when we only want to operate on the sourceMap */
boolean isInitialized(){
return this.initialized
}
@Override
public Object put(String key, Object value) {
//if its a map then build it first so it can go into the normal map.put and replace otherwise it ends up getting merged
if(value instanceof Map) buildIfNeeded()
if (map == null) {
return sourceMap.put(key, value)
} else {
return map.put(key, value)
}
}
/** call Maps.putValue */
public void putByPath(String key, Object value) {
if (map == null) {
sourceMap.put(key, value)
} else {
Maps.putValue(map, key, value, pathDelimiter)
}
}
@Override
public Set> entrySet() {
buildIfNeeded();
return map.entrySet();
}
@Override
public int size() {
if (map == null) {
return sourceMap.size()
} else {
return map.size()
}
}
@Override
public boolean isEmpty() {
if (map == null) {
return sourceMap.isEmpty();
} else {
return map.isEmpty();
}
}
@Override
public boolean containsValue(Object value) {
buildIfNeeded();
return map.containsValue(value);
}
@Override
public boolean containsKey(Object key) {
buildIfNeeded();
return map.containsKey(key);
}
@Override
public Object get(Object key) {
buildIfNeeded();
return map.get(key);
}
public void buildIfNeeded() {
if (map == null) {
map = new LinkedHashMap(sourceMap.size(), 0.01f);
//create keySet copy so we can modify as we iterate and dont get concurent modifcation exception
var keySetCopy = sourceMap.keySet().collect{it}
for (String key : keySetCopy) {
var sval = sourceMap[key]
if(sval instanceof LazyPathKeyMap){
sval.buildIfNeeded()
putByPath(key, sval)
}
else if(sval instanceof Map){
// it under the __merge__ key for now
Map mres = Maps.putValue(map, "${key}${pathDelimiter}~~MERGE~~", "MERGE_ME", pathDelimiter)
mres.remove("~~MERGE~~") //remove it
Maps.merge(mres, LazyPathKeyMap.of(sval as Map, pathDelimiter) )
//putByPath(key, LazyPathKeyMap.of(sval, pathDelimiter))
} else {
//key will probably have a dot
putByPath(key, sval)
}
}
sourceMap = null
initialized = true
}
}
@Override
public Object remove(Object key) {
buildIfNeeded();
return map.remove(key);
}
@Override
public void putAll(Map m) {
buildIfNeeded()
map.putAll(m)
}
@Override
public void clear() {
if (map == null) {
sourceMap.clear()
} else {
map.clear()
}
}
@Override
public Set keySet() {
buildIfNeeded()
return map.keySet()
}
@Override
public Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy