package sk.stuba.fiit.perconik.utilities; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.annotation.Nonnull; import com.google.common.base.Equivalence; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.base.Supplier; import com.google.common.collect.Maps; import static java.util.Arrays.asList; import static com.google.common.collect.Maps.newHashMapWithExpectedSize; /** * Static utility methods pertaining to {@code Map} instances. * * @author Pavol Zbell * @since 1.0 */ public final class MoreMaps { private MoreMaps() {} public static <K, V> HashMap<Equivalence.Wrapper<K>, V> newHashMap(final Equivalence<? super K> equivalence, final Iterable<? extends Entry<? extends K, ? extends V>> entries) { HashMap<Equivalence.Wrapper<K>, V> map = newHashMapExpectedFor(entries); wrapAll(map, equivalence, entries); return map; } public static <K, V> HashMap<K, V> newHashMap(final Iterable<? extends Entry<Equivalence.Wrapper<? extends K>, ? extends V>> entries) { HashMap<K, V> map = newHashMapExpectedFor(entries); unwrapAll(map, entries); return map; } public static <K, V> HashMap<K, V> newHashMapExpectedFor(final Iterable<?> iterable) { if (iterable instanceof Collection) { return newHashMapWithExpectedSize(((Collection<?>) iterable).size()); } return Maps.newHashMap(); } public static <K, V> LinkedHashMap<Equivalence.Wrapper<K>, V> newLinkedHashMap(final Equivalence<? super K> equivalence, final Iterable<? extends Entry<? extends K, ? extends V>> entries) { LinkedHashMap<Equivalence.Wrapper<K>, V> map = Maps.newLinkedHashMap(); wrapAll(map, equivalence, entries); return map; } public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(final Iterable<? extends Entry<Equivalence.Wrapper<? extends K>, ? extends V>> entries) { LinkedHashMap<K, V> map = Maps.newLinkedHashMap(); unwrapAll(map, entries); return map; } private static <K, V> void copy(final Dictionary<? extends K, ? extends V> from, final Map<K, V> to) { Enumeration<? extends K> keys = from.keys(); while (keys.hasMoreElements()) { K key = keys.nextElement(); to.put(key, from.get(key)); } } public static <K, V> Map<K, V> fromDictionary(final Dictionary<K, V> dictionary) { Map<K, V> map = newHashMapWithExpectedSize(dictionary.size()); copy(dictionary, map); return map; } public static Map<String, Object> flatten(final Map<?, Object> map) { return flatten(map, Joiner.on(".")); } public static Map<String, Object> flatten(final Map<?, Object> map, final Joiner joiner) { return flatten(map, joiner, Maps.<String, Object>newLinkedHashMap()); } public static Map<String, Object> flatten(final Map<?, Object> map, final Joiner joiner, final Map<String, Object> result) { return flatten(map, joiner, result, (String) null); } public static Map<String, Object> flatten(final Map<?, Object> map, final Joiner joiner, final Supplier<? extends Map<String, Object>> supplier) { return flatten(map, joiner, supplier.get()); } @SuppressWarnings("unchecked") private static Map<String, Object> flatten(final Map<?, Object> map, final Joiner joiner, final Map<String, Object> result, final String prefix) { for (Entry<?, Object> entry: map.entrySet()) { String key = prefix != null ? joiner.join(prefix, entry.getKey()) : joiner.join(asList(entry.getKey())); Object value = entry.getValue(); if (value instanceof Map) { flatten(((Map<?, Object>) value), joiner, result, key); } else { result.put(key, value); } } return result; } public static Map<String, Object> structure(final Map<?, ?> map) { return structure(map, Splitter.on(".").trimResults().omitEmptyStrings()); } public static Map<String, Object> structure(final Map<?, ?> map, final Splitter splitter) { return structure(map, splitter, new Supplier<Map<String, Object>>() { public Map<String, Object> get() { return Maps.newLinkedHashMap(); } }); } public static Map<String, Object> structure(final Map<?, ?> map, final Splitter splitter, final Supplier<? extends Map<String, Object>> supplier) { Map<String, Object> result = supplier.get(); for (Entry<?, ?> entry: map.entrySet()) { Object value = entry.getValue(); if (value instanceof Map) { value = structure((Map<?, ?>) value, splitter, supplier); } List<String> keys = splitter.splitToList(entry.getKey().toString()); int last = keys.size() - 1; Map<String, Object> submap; if (last == 0) { submap = result; } else { submap = substructure(result, keys.subList(0, last), supplier); } submap.put(keys.get(last), value); } return result; } @SuppressWarnings("unchecked") private static Map<String, Object> substructure(final Map<String, Object> map, final Iterable<String> keys, final Supplier<? extends Map<String, Object>> supplier) { Map<String, Object> submap = map; for (String key: keys) { Object value = submap.get(key); if (value instanceof Map) { submap = (Map<String, Object>) value; } else { Map<String, Object> link = supplier.get(); submap.put(key, link); submap = link; } } return submap; } public static <K, V> void putAll(final Map<K, V> map, final Iterable<? extends Entry<? extends K, ? extends V>> entries) { for (Entry<? extends K, ? extends V> entry: entries) { map.put(entry.getKey(), entry.getValue()); } } public static <K, V> void putAll(final Map<K, V> map, final Iterator<? extends Entry<? extends K, ? extends V>> entries) { while (entries.hasNext()) { Entry<? extends K, ? extends V> entry = entries.next(); map.put(entry.getKey(), entry.getValue()); } } public static <K, V> void wrapAll(final Map<Equivalence.Wrapper<K>, V> map, final Equivalence<? super K> equivalence, final Iterable<? extends Entry<? extends K, ? extends V>> entries) { for (Entry<? extends K, ? extends V> entry: entries) { map.put(equivalence.wrap((K) entry.getKey()), entry.getValue()); } } public static <K, V> void unwrapAll(final Map<K, V> map, final Iterable<? extends Entry<Equivalence.Wrapper<? extends K>, ? extends V>> entries) { for (Entry<Equivalence.Wrapper<? extends K>, ? extends V> entry: entries) { map.put(entry.getKey().get(), entry.getValue()); } } public static Map<String, Object> toProperties(final Map<?, ?> map) { return toProperties(map, Maps.<String, Object>newLinkedHashMap()); } public static Map<String, Object> toProperties(final Map<?, ?> map, final Map<String, Object> result) { for (Entry<?, ?> entry: map.entrySet()) { result.put(entry.getKey().toString(), entry.getValue()); } return result; } public static Map<String, Object> toProperties(final Map<?, ?> map, final Supplier<? extends Map<String, Object>> supplier) { return toProperties(map, supplier.get()); } private enum ToKeyFunction implements Function<Entry<Object, Object>, Object> { INSTANCE; public Object apply(@Nonnull final Entry<Object, Object> entry) { return entry.getKey(); } } private enum ToValueFunction implements Function<Entry<Object, Object>, Object> { INSTANCE; public Object apply(@Nonnull final Entry<Object, Object> entry) { return entry.getValue(); } } public static <E extends Entry<? extends K, ?>, K> Function<E, K> toKeyFunction() { @SuppressWarnings("unchecked") Function<E, K> result = (Function<E, K>) ToKeyFunction.INSTANCE; return result; } public static <E extends Entry<?, ? extends V>, V> Function<E, V> toValueFunction() { @SuppressWarnings("unchecked") Function<E, V> result = (Function<E, V>) ToValueFunction.INSTANCE; return result; } }