com.fireflysource.common.collection.map.MultiMap Maven / Gradle / Ivy
package com.fireflysource.common.collection.map;
import java.util.*;
/**
* A multi valued Map.
*
* @param the entry type for multimap values
*/
public class MultiMap extends HashMap> {
private static final long serialVersionUID = -1127515104096783129L;
public MultiMap() {
super();
}
public MultiMap(Map> map) {
super(map);
}
public MultiMap(MultiMap map) {
super(map);
}
/**
* Get multiple values. Single valued entries are converted to singleton
* lists.
*
* @param name The entry key.
* @return Unmodifieable List of values.
*/
public List getValues(String name) {
List vals = super.get(name);
if ((vals == null) || vals.isEmpty()) {
return null;
}
return vals;
}
/**
* Get a value from a multiple value. If the value is not a multivalue, then
* index 0 retrieves the value or null.
*
* @param name The entry key.
* @param i Index of element to get.
* @return Unmodifieable List of values.
*/
public V getValue(String name, int i) {
List vals = getValues(name);
if (vals == null) {
return null;
}
if (i == 0 && vals.isEmpty()) {
return null;
}
return vals.get(i);
}
/**
* Get value as String. Single valued items are converted to a String with
* the toString() Object method. Multi valued entries are converted to a
* comma separated List. No quoting of commas within values is performed.
*
* @param name The entry key.
* @return String value.
*/
public String getString(String name) {
List vals = get(name);
if ((vals == null) || (vals.isEmpty())) {
return null;
}
if (vals.size() == 1) {
// simple form.
return vals.get(0).toString();
}
// delimited form
StringBuilder values = new StringBuilder(128);
for (V e : vals) {
if (e != null) {
if (values.length() > 0)
values.append(',');
values.append(e.toString());
}
}
return values.toString();
}
/**
* Put multi valued entry.
*
* @param name The entry key.
* @param value The simple value
* @return The previous value or null.
*/
public List put(String name, V value) {
if (value == null) {
return super.put(name, null);
}
List vals = new ArrayList<>();
vals.add(value);
return put(name, vals);
}
/**
* Shorthand version of putAll
*
* @param input the input map
*/
public void putAllValues(Map input) {
for (Entry entry : input.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
/**
* Put multi valued entry.
*
* @param name The entry key.
* @param values The List of multiple values.
* @return The previous value or null.
*/
public List putValues(String name, List values) {
return super.put(name, values);
}
/**
* Put multi valued entry.
*
* @param name The entry key.
* @param values The array of multiple values.
* @return The previous value or null.
*/
@SafeVarargs
public final List putValues(String name, V... values) {
List list = new ArrayList<>();
list.addAll(Arrays.asList(values));
return super.put(name, list);
}
/**
* Add value to multi valued entry. If the entry is single valued, it is
* converted to the first value of a multi valued entry.
*
* @param name The entry key.
* @param value The entry value.
*/
public void add(String name, V value) {
List lo = get(name);
if (lo == null) {
lo = new ArrayList<>();
}
lo.add(value);
super.put(name, lo);
}
/**
* Add values to multi valued entry. If the entry is single valued, it is
* converted to the first value of a multi valued entry.
*
* @param name The entry key.
* @param values The List of multiple values.
*/
public void addValues(String name, List values) {
List lo = get(name);
if (lo == null) {
lo = new ArrayList<>();
}
lo.addAll(values);
put(name, lo);
}
/**
* Add values to multi valued entry. If the entry is single valued, it is
* converted to the first value of a multi valued entry.
*
* @param name The entry key.
* @param values The String array of multiple values.
*/
public void addValues(String name, V[] values) {
List lo = get(name);
if (lo == null) {
lo = new ArrayList<>();
}
lo.addAll(Arrays.asList(values));
put(name, lo);
}
/**
* Merge values.
*
* @param map the map to overlay on top of this one, merging together values
* if needed.
* @return true if an existing key was merged with potentially new values,
* false if either no change was made, or there were only new keys.
*/
public boolean addAllValues(MultiMap map) {
boolean merged = false;
if ((map == null) || (map.isEmpty())) {
// done
return merged;
}
for (Entry> entry : map.entrySet()) {
String name = entry.getKey();
List values = entry.getValue();
if (this.containsKey(name)) {
merged = true;
}
this.addValues(name, values);
}
return merged;
}
/**
* Remove value.
*
* @param name The entry key.
* @param value The entry value.
* @return true if it was removed.
*/
public boolean removeValue(String name, V value) {
List lo = get(name);
if ((lo == null) || (lo.isEmpty())) {
return false;
}
boolean ret = lo.remove(value);
if (lo.isEmpty()) {
remove(name);
} else {
put(name, lo);
}
return ret;
}
/**
* Test for a specific single value in the map.
*
* NOTE: This is a SLOW operation, and is actively discouraged.
*
* @param value the value to search for
* @return true if contains simple value
*/
public boolean containsSimpleValue(V value) {
for (List vals : values()) {
if ((vals.size() == 1) && vals.contains(value)) {
return true;
}
}
return false;
}
@Override
public String toString() {
Iterator>> iter = entrySet().iterator();
StringBuilder sb = new StringBuilder();
sb.append('{');
boolean delim = false;
while (iter.hasNext()) {
Entry> e = iter.next();
if (delim) {
sb.append(", ");
}
String key = e.getKey();
List vals = e.getValue();
sb.append(key);
sb.append('=');
if (vals.size() == 1) {
sb.append(vals.get(0));
} else {
sb.append(vals);
}
delim = true;
}
sb.append('}');
return sb.toString();
}
/**
* @return Map of String arrays
*/
public Map toStringArrayMap() {
HashMap map = new HashMap(size() * 3 / 2) {
private static final long serialVersionUID = -6129887569971781626L;
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append('{');
for (String k : super.keySet()) {
if (b.length() > 1)
b.append(',');
b.append(k);
b.append('=');
b.append(Arrays.asList(super.get(k)));
}
b.append('}');
return b.toString();
}
};
for (Entry> entry : entrySet()) {
String[] a = null;
if (entry.getValue() != null) {
a = new String[entry.getValue().size()];
a = entry.getValue().toArray(a);
}
map.put(entry.getKey(), a);
}
return map;
}
}