package alien4cloud.utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import alien4cloud.exception.InvalidArgumentException;
import alien4cloud.rest.utils.JsonUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Maps;
/**
* Utility class to ease map manipulation.
*/
public final class MapUtil {
private MapUtil() {
}
/**
* Map.putall with non null check on the other map.
*
* @param map The map in which to put data.
* @param otherMap The map to merge in the first map (may be null).
* @param <K> Type of keys.
* @param <V> Type of values.
*/
public static <K, V> void putAll(Map<K, V> map, Map<K, V> otherMap) {
if (otherMap != null) {
map.putAll(otherMap);
}
}
/**
* This method allows to add an element to the list of elements in a map for a given key. If the list is null for the given key it will create a new list,
* insert it in the map and add the element.
*
* @param listMap A map of <Key, List<Values>>
* @param key The key in the map.
* @param value The element to add to the list that is mapped by the given key.
* @param <K> The key class.
* @param <V> The class of the list elements.
*/
public static <K, V> void addToList(Map<K, List<V>> listMap, K key, V value) {
List<V> list = listMap.get(key);
if (list == null) {
list = new ArrayList<V>();
listMap.put(key, list);
}
list.add(value);
}
/**
* Try to get a value following a path in a map or a list/array. For example :
* MapUtil.get(map, "a.b.c") correspond to:
* map.get(a).get(b).get(c)
* MapUtil.get(list, "1.b.c.2") correspond to:
* list[1].get(b).get(c)[2]
*
* @param object the map/list to search for path
* @param path keys in the map separated by '.'
*/
public static Object get(Object object, String path) {
if (StringUtils.isBlank(path)) {
throw new InvalidArgumentException("Path is empty, cannot evaluate property for object " + object);
}
String[] tokens = path.split("[\\.\\]\\[]");
return get(object, tokens);
}
/**
* Try to get a value following a path of tokens in a map or a list/array.
*
* @param object the map/list to search for path
* @param tokens keys in the map
*/
public static Object get(Object object, String... tokens) {
Object value = object;
for (String token : tokens) {
if (StringUtils.isEmpty(token)) {
continue;
}
if (value instanceof List) {
List<Object> nested = (List<Object>) value;
try {
int index = Integer.parseInt(token);
value = nested.get(index);
if (value == null) {
return null;
}
} catch (NumberFormatException e) {
return null;
}
} else if (value instanceof Object[]) {
Object[] nested = (Object[]) value;
try {
int index = Integer.parseInt(token);
value = nested[index];
if (value == null) {
return null;
}
} catch (NumberFormatException e) {
return null;
}
} else if (value instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> nested = (Map<String, Object>) value;
value = nested.get(token);
if (value == null) {
return null;
}
} else {
return null;
}
}
return value;
}
/**
* Create a new hash map and fills it from the given keys and values (keys[index] -> values[index].
*
* @param keys The array of keys.
* @param values The array of values.
* @return A map that contains for each key element in the keys array a value from the values array at the same index.
*/
public static <K, V> Map<K, V> newHashMap(K[] keys, V[] values) {
Map<K, V> map = new HashMap<K, V>();
if (keys == null || values == null || keys.length != values.length) {
throw new IllegalArgumentException("keys and values must be non-null and have the same size.");
}
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
return map;
}
/**
* Revert a map key --> value become value --> key
*
* @param map the map to revert
* @param <K> the type of the key
* @param <V> the type of the value
* @return reverted map
*/
public static <K, V> Map<V, K> revert(Map<K, V> map) {
Map<V, K> reverted = new HashMap<V, K>();
for (Map.Entry<K, V> entry : map.entrySet()) {
reverted.put(entry.getValue(), entry.getKey());
}
return reverted;
}
/**
* Remove the entry with 'oldKey' and put it (if exists) using 'newKey' unless if an entry already exist for 'newKey'.
*/
public static <K, V> void replaceKey(Map<K, V> map, K oldKey, K newKey) {
if (map == null || map.isEmpty()) {
return;
}
if (map.containsKey(newKey)) {
return;
}
V o = map.remove(oldKey);
if (o != null) {
map.put(newKey, o);
}
}
public static Map<String, String> toString(Map<String, Object> stringObjectMap) throws JsonProcessingException {
Map<String, String> stringStringMap = Maps.newHashMap();
for (Map.Entry<String, Object> stringObjectEntry : stringObjectMap.entrySet()) {
if (stringObjectEntry.getValue() != null) {
if (stringObjectEntry.getValue() instanceof String) {
stringStringMap.put(stringObjectEntry.getKey(), (String) stringObjectEntry.getValue());
} else {
stringStringMap.put(stringObjectEntry.getKey(), JsonUtil.toString(stringObjectEntry.getValue()));
}
} else {
stringStringMap.put(stringObjectEntry.getKey(), null);
}
}
return stringStringMap;
}
}