diff --git a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
index bf30d9006..5fdee52c1 100644
--- a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
+++ b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
@@ -23,7 +23,8 @@ import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.bag.HashBag;
-import org.apache.commons.collections4.multimap.MultiValuedHashMap;
+import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
+import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.collections4.multimap.TransformedMultiValuedMap;
import org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap;
@@ -52,7 +53,7 @@ public class MultiMapUtils {
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP =
- UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new MultiValuedHashMap());
+ UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0));
/**
* Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety.
@@ -188,21 +189,7 @@ public class MultiMapUtils {
* @return a new ListValuedMap
*/
public static ListValuedMap newListValuedHashMap() {
- return MultiValuedHashMap.listValuedHashMap();
- }
-
- /**
- * Creates a {@link ListValuedMap} with a {@link java.util.HashMap HashMap} as its internal
- * storage which maps the keys to list of type listClass.
- *
- * @param the key type
- * @param the value type
- * @param the List class type
- * @param listClass the class of the list
- * @return a new {@link ListValuedMap}
- */
- public static > ListValuedMap newListValuedHashMap(final Class listClass) {
- return MultiValuedHashMap.listValuedHashMap(listClass);
+ return new ArrayListValuedHashMap();
}
/**
@@ -214,21 +201,7 @@ public class MultiMapUtils {
* @return a new {@link SetValuedMap}
*/
public static SetValuedMap newSetValuedHashMap() {
- return MultiValuedHashMap.setValuedHashMap();
- }
-
- /**
- * Creates a {@link SetValuedMap} with a {@link java.util.HashMap HashMap} as its internal
- * storage which maps the keys to a set of type setClass
- *
- * @param the key type
- * @param the value type
- * @param the Set class type
- * @param setClass the class of the set
- * @return a new {@link SetValuedMap}
- */
- public static > SetValuedMap newSetValuedHashMap(final Class setClass) {
- return MultiValuedHashMap.setValuedHashMap(setClass);
+ return new HashSetValuedHashMap();
}
// MultiValuedMap Decorators
diff --git a/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java b/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
index dd1014eb4..d5e3237a3 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractListValuedMap.java
@@ -38,34 +38,28 @@ import org.apache.commons.collections4.ListValuedMap;
public abstract class AbstractListValuedMap extends AbstractMultiValuedMap
implements ListValuedMap {
- /** The serialization version */
- private static final long serialVersionUID = 20150612L;
-
/**
- * A constructor that wraps, not copies
- *
- * @param the list type
- * @param map the map to wrap, must not be null
- * @param listClazz the collection class
- * @throws NullPointerException if the map is null
+ * Constructor needed for subclass serialisation.
*/
- protected > AbstractListValuedMap(final Map map, Class listClazz) {
- super(map, listClazz);
+ protected AbstractListValuedMap() {
+ super();
}
/**
* A constructor that wraps, not copies
*
- * @param the list type
* @param map the map to wrap, must not be null
- * @param listClazz the collection class
- * @param initialListCapacity the initial size of the values list
- * @throws NullPointerException if the map is null
- * @throws IllegalArgumentException if initialListCapacity is negative
+ * @throws NullPointerException if the map is null
*/
- protected > AbstractListValuedMap(final Map map, Class listClazz,
- final int initialListCapacity) {
- super(map, listClazz, initialListCapacity);
+ protected AbstractListValuedMap(final Map> map) {
+ super(map);
+ }
+
+ // -----------------------------------------------------------------------
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Map> getMap() {
+ return (Map>) super.getMap();
}
/**
@@ -73,10 +67,9 @@ public abstract class AbstractListValuedMap extends AbstractMultiValuedMap
* @return a new list
*/
@Override
- protected List createCollection() {
- return (List) super.createCollection();
- }
+ protected abstract List createCollection();
+ // -----------------------------------------------------------------------
/**
* Gets the list of values associated with the specified key. This would
* return an empty list in case the mapping is not present
@@ -100,25 +93,10 @@ public abstract class AbstractListValuedMap extends AbstractMultiValuedMap
*/
@Override
public List remove(Object key) {
- return ListUtils.emptyIfNull((List) getMap().remove(key));
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof ListValuedMap) {
- return asMap().equals(((ListValuedMap, ?>) obj).asMap());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return asMap().hashCode();
+ return ListUtils.emptyIfNull(getMap().remove(key));
}
+ // -----------------------------------------------------------------------
/**
* Wrapped list to handle add and remove on the list returned by get(object)
*/
@@ -130,7 +108,7 @@ public abstract class AbstractListValuedMap extends AbstractMultiValuedMap
@Override
protected List getMapping() {
- return (List) getMap().get(key);
+ return getMap().get(key);
}
@Override
@@ -237,13 +215,13 @@ public abstract class AbstractListValuedMap extends AbstractMultiValuedMap
public ValuesListIterator(final K key) {
this.key = key;
- this.values = ListUtils.emptyIfNull((List) getMap().get(key));
+ this.values = ListUtils.emptyIfNull(getMap().get(key));
this.iterator = values.listIterator();
}
public ValuesListIterator(final K key, int index) {
this.key = key;
- this.values = ListUtils.emptyIfNull((List) getMap().get(key));
+ this.values = ListUtils.emptyIfNull(getMap().get(key));
this.iterator = values.listIterator(index);
}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
index fe0a77076..f1a1e5a01 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java
@@ -16,7 +16,9 @@
*/
package org.apache.commons.collections4.multimap;
-import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.AbstractCollection;
import java.util.ArrayList;
@@ -27,13 +29,11 @@ import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Factory;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.MapIterator;
import org.apache.commons.collections4.MultiSet;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.Transformer;
-import org.apache.commons.collections4.functors.InstantiateFactory;
import org.apache.commons.collections4.iterators.EmptyMapIterator;
import org.apache.commons.collections4.iterators.IteratorChain;
import org.apache.commons.collections4.iterators.LazyIteratorChain;
@@ -50,13 +50,7 @@ import org.apache.commons.collections4.set.UnmodifiableSet;
* @since 4.1
* @version $Id$
*/
-public abstract class AbstractMultiValuedMap implements MultiValuedMap, Serializable {
-
- /** Serialization Version */
- private static final long serialVersionUID = 20150612L;
-
- /** The factory for creating value collections. */
- private final Factory extends Collection> collectionFactory;
+public abstract class AbstractMultiValuedMap implements MultiValuedMap {
/** The values view */
private transient Collection valuesView;
@@ -68,60 +62,55 @@ public abstract class AbstractMultiValuedMap implements MultiValuedMap> map;
+ private transient Map> map;
+
+ /**
+ * Constructor needed for subclass serialisation.
+ */
+ protected AbstractMultiValuedMap() {
+ super();
+ }
/**
* Constructor that wraps (not copies).
*
* @param the collection type
* @param map the map to wrap, must not be null
- * @param collectionClazz the collection class
* @throws NullPointerException if the map is null
*/
@SuppressWarnings("unchecked")
- protected > AbstractMultiValuedMap(final Map map,
- final Class collectionClazz) {
+ protected AbstractMultiValuedMap(final Map> map) {
if (map == null) {
throw new NullPointerException("Map must not be null.");
}
this.map = (Map>) map;
- this.collectionFactory = new InstantiateFactory(collectionClazz);
- }
-
- /**
- * Constructor that wraps (not copies).
- *
- * @param the collection type
- * @param map the map to wrap, must not be null
- * @param collectionClazz the collection class
- * @param initialCollectionCapacity the initial capacity of the collection
- * @throws NullPointerException if the map is null
- * @throws IllegalArgumentException if initialCollectionCapacity is negative
- */
- @SuppressWarnings("unchecked")
- protected > AbstractMultiValuedMap(final Map map,
- final Class collectionClazz, final int initialCollectionCapacity) {
- if (map == null) {
- throw new NullPointerException("Map must not be null.");
- }
- if (initialCollectionCapacity < 0) {
- throw new IllegalArgumentException("InitialCapacity must not be negative.");
- }
- this.map = (Map>) map;
- this.collectionFactory = new InstantiateFactory(collectionClazz,
- new Class[] { Integer.TYPE },
- new Object[] { Integer.valueOf(initialCollectionCapacity) });
}
+ // -----------------------------------------------------------------------
/**
* Gets the map being wrapped.
*
* @return the wrapped map
*/
- protected Map> getMap() {
+ protected Map> getMap() {
return map;
}
+ /**
+ * Sets the map being wrapped.
+ *
+ * NOTE: this method should only be used during deserialization
+ *
+ * @param map the map to wrap
+ */
+ @SuppressWarnings("unchecked")
+ protected void setMap(Map> map) {
+ this.map = (Map>) map;
+ }
+
+ protected abstract Collection createCollection();
+
+ // -----------------------------------------------------------------------
@Override
public boolean containsKey(Object key) {
return getMap().containsKey(key);
@@ -250,7 +239,7 @@ public abstract class AbstractMultiValuedMap implements MultiValuedMap implements MultiValuedMap> asMap() {
- return getMap();
+ // TODO: return a view of the map
+ return (Map>) getMap();
}
/**
@@ -373,18 +364,12 @@ public abstract class AbstractMultiValuedMap implements MultiValuedMap createCollection() {
- return collectionFactory.create();
+ return asMap().toString();
}
// -----------------------------------------------------------------------
@@ -906,4 +891,44 @@ public abstract class AbstractMultiValuedMap implements MultiValuedMap> entry : map.entrySet()) {
+ out.writeObject(entry.getKey());
+ out.writeInt(entry.getValue().size());
+ for (final V value : entry.getValue()) {
+ out.writeObject(value);
+ }
+ }
+ }
+
+ /**
+ * Read the map in using a custom routine.
+ * @param in the input stream
+ * @throws IOException any of the usual I/O related exceptions
+ * @throws ClassNotFoundException if the stream contains an object which class can not be loaded
+ * @throws ClassCastException if the stream does not contain the correct objects
+ */
+ protected void doReadObject(final ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ final int entrySize = in.readInt();
+ for (int i = 0; i < entrySize; i++) {
+ @SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
+ final K key = (K) in.readObject();
+ final Collection values = get(key);
+ final int valueSize = in.readInt();
+ for (int j = 0; j < valueSize; j++) {
+ @SuppressWarnings("unchecked") // see above
+ V value = (V) in.readObject();
+ values.add(value);
+ }
+ }
+ }
+
}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
index 525cfc58c..ff520caa4 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java
@@ -61,6 +61,7 @@ public abstract class AbstractMultiValuedMapDecorator
this.map = map;
}
+ // -----------------------------------------------------------------------
/**
* The decorated multi-valued map.
*
@@ -70,6 +71,7 @@ public abstract class AbstractMultiValuedMapDecorator
return map;
}
+ // -----------------------------------------------------------------------
@Override
public int size() {
return decorated().size();
diff --git a/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java b/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
index 5355f6d66..bcfa20af3 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractSetValuedMap.java
@@ -36,36 +36,38 @@ import org.apache.commons.collections4.SetValuedMap;
public abstract class AbstractSetValuedMap extends AbstractMultiValuedMap
implements SetValuedMap {
- /** Serialization version */
- private static final long serialVersionUID = 20150612L;
-
/**
- * A constructor that wraps, not copies
- *
- * @param the set type
- * @param map the map to wrap, must not be null
- * @param setClazz the collection class
- * @throws NullPointerException if the map is null
+ * Constructor needed for subclass serialisation.
*/
- protected > AbstractSetValuedMap(Map map, Class setClazz) {
- super(map, setClazz);
+ protected AbstractSetValuedMap() {
+ super();
}
/**
* A constructor that wraps, not copies
*
- * @param the set type
* @param map the map to wrap, must not be null
- * @param setClazz the collection class
- * @param initialSetCapacity the initial size of the values set
* @throws NullPointerException if the map is null
- * @throws IllegalArgumentException if initialSetCapacity is negative
*/
- protected > AbstractSetValuedMap(Map map, Class setClazz,
- int initialSetCapacity) {
- super(map, setClazz, initialSetCapacity);
+ protected AbstractSetValuedMap(Map> map) {
+ super(map);
}
+ // -----------------------------------------------------------------------
+ @Override
+ @SuppressWarnings("unchecked")
+ protected Map> getMap() {
+ return (Map>) super.getMap();
+ }
+
+ /**
+ * Creates a new value collection using the provided factory.
+ * @return a new list
+ */
+ @Override
+ protected abstract Set createCollection();
+
+ // -----------------------------------------------------------------------
/**
* Gets the set of values associated with the specified key. This would
* return an empty set in case the mapping is not present
@@ -90,25 +92,10 @@ public abstract class AbstractSetValuedMap extends AbstractMultiValuedMap<
*/
@Override
public Set remove(Object key) {
- return SetUtils.emptyIfNull((Set) getMap().remove(key));
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof SetValuedMap) {
- return asMap().equals(((SetValuedMap, ?>) obj).asMap());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return asMap().hashCode();
+ return SetUtils.emptyIfNull(getMap().remove(key));
}
+ // -----------------------------------------------------------------------
/**
* Wrapped set to handle add and remove on the collection returned by
* {@code get(Object)}.
diff --git a/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
new file mode 100644
index 000000000..2d4fa648a
--- /dev/null
+++ b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
@@ -0,0 +1,128 @@
+package org.apache.commons.collections4.multimap;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.collections4.ListValuedMap;
+import org.apache.commons.collections4.MultiValuedMap;
+
+/**
+ * Implements a {@link ListValuedMap}, using a {@link HashMap} to provide data
+ * storage and {@link ArrayList}s as value collections. This is the standard
+ * implementation of a ListValuedMap.
+ *
+ * Note that ArrayListValuedHashMap is not synchronized and is not
+ * thread-safe. If you wish to use this map from multiple threads
+ * concurrently, you must use appropriate synchronization. This class may throw
+ * exceptions when accessed by concurrent threads without synchronization.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class ArrayListValuedHashMap extends AbstractListValuedMap
+ implements Serializable {
+
+ /** Serialization Version */
+ private static final long serialVersionUID = 20151118L;
+
+ /**
+ * The initial map capacity used when none specified in constructor.
+ */
+ private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
+
+ /**
+ * The initial list capacity when using none specified in constructor.
+ */
+ private static final int DEFAULT_INITIAL_LIST_CAPACITY = 3;
+
+ /**
+ * The initial list capacity when creating a new value collection.
+ */
+ private final int initialListCapacity;
+
+ /**
+ * Creates an empty ArrayListValuedHashMap with the default initial
+ * map capacity (16) and the default initial list capacity (3).
+ */
+ public ArrayListValuedHashMap() {
+ this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_LIST_CAPACITY);
+ }
+
+ /**
+ * Creates an empty ArrayListValuedHashMap with the default initial
+ * map capacity (16) and the specified initial list capacity.
+ *
+ * @param initialListCapacity the initial capacity used for value collections
+ */
+ public ArrayListValuedHashMap(int initialListCapacity) {
+ this(DEFAULT_INITIAL_MAP_CAPACITY, initialListCapacity);
+ }
+
+ /**
+ * Creates an empty ArrayListValuedHashMap with the specified initial
+ * map and list capacities.
+ *
+ * @param initialMapCapacity the initial hashmap capacity
+ * @param initialListCapacity the initial capacity used for value collections
+ */
+ public ArrayListValuedHashMap(int initialMapCapacity, int initialListCapacity) {
+ super(new HashMap>(initialMapCapacity));
+ this.initialListCapacity = initialListCapacity;
+ }
+
+ /**
+ * Creates an ArrayListValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a MultiValuedMap to copy into this map
+ */
+ public ArrayListValuedHashMap(final MultiValuedMap extends K, ? extends V> map) {
+ this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY);
+ super.putAll(map);
+ }
+
+ /**
+ * Creates an ArrayListValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a Map to copy into this map
+ */
+ public ArrayListValuedHashMap(final Map extends K, ? extends V> map) {
+ this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY);
+ super.putAll(map);
+ }
+
+ // -----------------------------------------------------------------------
+ @Override
+ protected ArrayList createCollection() {
+ return new ArrayList(initialListCapacity);
+ }
+
+ // -----------------------------------------------------------------------
+ /**
+ * Trims the capacity of all value collections to their current size.
+ */
+ public void trimToSize() {
+ for (Collection coll : getMap().values()) {
+ final ArrayList list = (ArrayList) coll;
+ list.trimToSize();
+ }
+ }
+
+ // -----------------------------------------------------------------------
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.defaultWriteObject();
+ doWriteObject(oos);
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ ois.defaultReadObject();
+ setMap(new HashMap>());
+ doReadObject(ois);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java b/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
new file mode 100644
index 000000000..5737368c8
--- /dev/null
+++ b/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
@@ -0,0 +1,116 @@
+package org.apache.commons.collections4.multimap;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.apache.commons.collections4.MultiValuedMap;
+import org.apache.commons.collections4.SetValuedMap;
+
+/**
+ * Implements a {@link SetValuedMap}, using a {@link HashMap} to provide data
+ * storage and {@link HashSet}s as value collections. This is the standard
+ * implementation of a SetValuedMap.
+ *
+ * Note that HashSetValuedHashMap is not synchronized and is not
+ * thread-safe. If you wish to use this map from multiple threads
+ * concurrently, you must use appropriate synchronization. This class may throw
+ * exceptions when accessed by concurrent threads without synchronization.
+ *
+ * @since 4.1
+ * @version $Id$
+ */
+public class HashSetValuedHashMap extends AbstractSetValuedMap
+ implements Serializable {
+
+ /** Serialization Version */
+ private static final long serialVersionUID = 20151118L;
+
+ /**
+ * The initial map capacity used when none specified in constructor.
+ */
+ private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
+
+ /**
+ * The initial set capacity when using none specified in constructor.
+ */
+ private static final int DEFAULT_INITIAL_SET_CAPACITY = 3;
+
+ /**
+ * The initial list capacity when creating a new value collection.
+ */
+ private final int initialSetCapacity;
+
+ /**
+ * Creates an empty HashSetValuedHashMap with the default initial
+ * map capacity (16) and the default initial set capacity (3).
+ */
+ public HashSetValuedHashMap() {
+ this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_SET_CAPACITY);
+ }
+
+ /**
+ * Creates an empty HashSetValuedHashMap with the default initial
+ * map capacity (16) and the specified initial set capacity.
+ *
+ * @param initialSetCapacity the initial capacity used for value collections
+ */
+ public HashSetValuedHashMap(int initialSetCapacity) {
+ this(DEFAULT_INITIAL_MAP_CAPACITY, initialSetCapacity);
+ }
+
+ /**
+ * Creates an empty HashSetValuedHashMap with the specified initial
+ * map and list capacities.
+ *
+ * @param initialMapCapacity the initial hashmap capacity
+ * @param initialSetCapacity the initial capacity used for value collections
+ */
+ public HashSetValuedHashMap(int initialMapCapacity, int initialSetCapacity) {
+ super(new HashMap>(initialMapCapacity));
+ this.initialSetCapacity = initialSetCapacity;
+ }
+
+ /**
+ * Creates an HashSetValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a MultiValuedMap to copy into this map
+ */
+ public HashSetValuedHashMap(final MultiValuedMap extends K, ? extends V> map) {
+ this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
+ super.putAll(map);
+ }
+
+ /**
+ * Creates an HashSetValuedHashMap copying all the mappings of the given map.
+ *
+ * @param map a Map to copy into this map
+ */
+ public HashSetValuedHashMap(final Map extends K, ? extends V> map) {
+ this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
+ super.putAll(map);
+ }
+
+ // -----------------------------------------------------------------------
+ @Override
+ protected HashSet createCollection() {
+ return new HashSet(initialSetCapacity);
+ }
+
+ // -----------------------------------------------------------------------
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.defaultWriteObject();
+ doWriteObject(oos);
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ ois.defaultReadObject();
+ setMap(new HashMap>());
+ doReadObject(ois);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java b/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
deleted file mode 100644
index d0a5704a9..000000000
--- a/src/main/java/org/apache/commons/collections4/multimap/MultiValuedHashMap.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.collections4.multimap;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.collections4.ListValuedMap;
-import org.apache.commons.collections4.MultiValuedMap;
-import org.apache.commons.collections4.SetValuedMap;
-
-/**
- * Implements a {@link MultiValuedMap}, using a {@link HashMap} to provide data
- * storage. This is the standard implementation of a MultiValuedMap
- *
- * A MultiValuedMap is a Map with slightly different semantics.
- * Putting a value into the map will add the value to a Collection at that key.
- * Getting a value will return a Collection, holding all the values put to that
- * key
- *
- * In addition, this implementation allows the type of collection used for the
- * values to be controlled. By default, an ArrayList is used,
- * however a Class extends Collection> to instantiate the value
- * collection may be specified.
- *
- * Note that MultiValuedHashMap is not synchronized and is not
- * thread-safe. If you wish to use this map from multiple threads
- * concurrently, you must use appropriate synchronization. This class may throw
- * exceptions when accessed by concurrent threads without synchronization.
- *
- * @since 4.1
- * @version $Id$
- */
-public class MultiValuedHashMap extends AbstractMultiValuedMap {
-
- /** Serialization Version */
- private static final long serialVersionUID = 20150612L;
-
- /**
- * The initial capacity used when none specified in constructor.
- */
- static final int DEFAULT_INITIAL_CAPACITY = 16;
-
- /**
- * The load factor used when none specified in constructor.
- */
- static final float DEFAULT_LOAD_FACTOR = 0.75f;
-
- /**
- * Creates a {@link ListValuedMap} with a {@link HashMap} as its internal
- * storage
- *
- * @param the key type
- * @param the value type
- * @return a new ListValuedMap
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static ListValuedMap listValuedHashMap() {
- return new ListValuedHashMap(ArrayList.class);
- }
-
- /**
- * Creates a {@link ListValuedMap} with a {@link HashMap} as its internal
- * storage which maps the keys to list of type listClass
- *
- * @param the key type
- * @param the value type
- * @param the List class type
- * @param listClass the class of the list
- * @return a new ListValuedMap
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static > ListValuedMap listValuedHashMap(final Class listClass) {
- return new ListValuedHashMap(listClass);
- }
-
- /**
- * Creates a {@link SetValuedMap} with a {@link HashMap} as its internal
- * storage
- *
- * @param the key type
- * @param the value type
- * @return a new SetValuedMap
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static SetValuedMap setValuedHashMap() {
- return new SetValuedHashMap(HashSet.class);
- }
-
- /**
- * Creates a {@link SetValuedMap} with a {@link HashMap} as its internal
- * storage which maps the keys to a set of type setClass
- *
- * @param the key type
- * @param the value type
- * @param the Set class type
- * @param setClass the class of the set
- * @return a new SetValuedMap
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public static > SetValuedMap setValuedHashMap(final Class setClass) {
- return new SetValuedHashMap(setClass);
- }
-
- /**
- * Creates a MultiValueMap based on a HashMap with the default
- * initial capacity (16) and the default load factor (0.75), which stores
- * the multiple values in an ArrayList.
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap() {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
- }
-
- /**
- * Creates a MultiValueMap based on a HashMap with the initial
- * capacity and the default load factor (0.75), which stores the multiple
- * values in an ArrayList.
- *
- * @param initialCapacity the initial capacity of the underlying hash map
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR, ArrayList.class);
- }
-
- /**
- * Creates a MultiValueMap based on a HashMap with the initial
- * capacity and the load factor, which stores the multiple values in an
- * ArrayList.
- *
- * @param initialCapacity the initial capacity of the underlying hash map
- * @param loadFactor the load factor of the underlying hash map
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap(int initialCapacity, float loadFactor) {
- this(initialCapacity, loadFactor, ArrayList.class);
- }
-
- /**
- * Creates a MultiValueMap based on a HashMap with the initial
- * capacity and the load factor, which stores the multiple values in an
- * ArrayList with the initial collection capacity.
- *
- * @param initialCapacity the initial capacity of the underlying hash map
- * @param loadFactor the load factor of the underlying hash map
- * @param initialCollectionCapacity the initial capacity of the Collection of values
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap(int initialCapacity, float loadFactor, int initialCollectionCapacity) {
- this(initialCapacity, loadFactor, ArrayList.class, initialCollectionCapacity);
- }
-
- /**
- * Creates a MultiValuedHashMap copying all the mappings of the given map.
- *
- * @param map a MultiValuedMap to copy into this map
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap(final MultiValuedMap extends K, ? extends V> map) {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
- super.putAll(map);
- }
-
- /**
- * Creates a MultiValuedHashMap copying all the mappings of the given map.
- *
- * @param map a Map to copy into this map
- */
- @SuppressWarnings("unchecked")
- public MultiValuedHashMap(final Map extends K, ? extends V> map) {
- this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, ArrayList.class);
- super.putAll(map);
- }
-
- /**
- * Creates a MultiValuedHashMap which creates the value collections using
- * the supplied collectionClazz.
- *
- * @param initialCapacity the initial capacity of the underlying
- * HashMap
- * @param loadFactor the load factor of the underlying HashMap
- * @param the collection type
- * @param collectionClazz the class of the Collection to use to
- * create the value collections
- */
- protected > MultiValuedHashMap(int initialCapacity, float loadFactor,
- final Class collectionClazz) {
- super(new HashMap>(initialCapacity, loadFactor), collectionClazz);
- }
-
- /**
- * Creates a MultiValuedHashMap which creates the value collections using
- * the supplied collectionClazz and the initial collection capacity.
- *
- * @param the collection type
- * @param initialCapacity the initial capacity of the underlying HashMap
- * @param loadFactor the load factor of the underlying HashMap
- * @param initialCollectionCapacity the initial capacity of the Collection
- * @param collectionClazz the class of the Collection to use to create the value collections
- */
- protected > MultiValuedHashMap(int initialCapacity, float loadFactor,
- final Class collectionClazz, int initialCollectionCapacity) {
- super(new HashMap>(initialCapacity, loadFactor), collectionClazz,
- initialCollectionCapacity);
- }
-
- /** Inner class for ListValuedMap */
- private static class ListValuedHashMap extends AbstractListValuedMap {
-
- private static final long serialVersionUID = 20150612L;
-
- public > ListValuedHashMap(Class listClazz) {
- super(new HashMap>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR), listClazz);
- }
-
- public > ListValuedHashMap(Class listClazz, int initialListCapacity) {
- super(new HashMap>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR), listClazz,
- initialListCapacity);
- }
-
- }
-
- /** Inner class for SetValuedMap */
- private static class SetValuedHashMap extends AbstractSetValuedMap {
-
- private static final long serialVersionUID = 20150612L;
-
- public > SetValuedHashMap(Class setClazz) {
- super(new HashMap>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR), setClazz);
- }
-
- public > SetValuedHashMap(Class setClazz, int initialSetCapacity) {
- super(new HashMap>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR), setClazz,
- initialSetCapacity);
- }
-
- }
-
-}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java b/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
index f0edd332d..93a4a8b38 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java
@@ -91,7 +91,7 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor
final TransformedMultiValuedMap decorated =
new TransformedMultiValuedMap(map, keyTransformer, valueTransformer);
if (!map.isEmpty()) {
- final MultiValuedMap mapCopy = new MultiValuedHashMap(map);
+ final MultiValuedMap mapCopy = new ArrayListValuedHashMap(map);
decorated.clear();
decorated.putAll(mapCopy);
}
diff --git a/src/main/java/org/apache/commons/collections4/multimap/package-info.java b/src/main/java/org/apache/commons/collections4/multimap/package-info.java
index ace5aa153..030d3fe17 100644
--- a/src/main/java/org/apache/commons/collections4/multimap/package-info.java
+++ b/src/main/java/org/apache/commons/collections4/multimap/package-info.java
@@ -20,9 +20,8 @@
*
* The following implementations are provided in the package:
*
- *
MultiValuedHashMap - implementation that uses a HashMap to store the data
- *
ListValuedHashMap - implementation of a ListValuedMap using a HashMap as data store
- *
SetValuedHashMap - implementation of a SetValuedMap using a HashMap as data store
+ *
ArrayListValuedHashMap - ListValuedMap implementation using a HashMap/ArrayList
+ *
HashSetValuedHashMap - SetValuedMap implementation using a HashMap/HashSet
*
*
* The following decorators are provided in the package:
diff --git a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
index 865052559..3ce5d9f00 100644
--- a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
@@ -26,7 +26,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
-import org.apache.commons.collections4.multimap.MultiValuedHashMap;
+import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.junit.Test;
/**
@@ -64,20 +64,20 @@ public class MultiMapUtilsTest {
public void testEmptyIfNull() {
assertTrue(MultiMapUtils.emptyIfNull(null).isEmpty());
- final MultiValuedMap map = new MultiValuedHashMap();
+ final MultiValuedMap map = new ArrayListValuedHashMap();
map.put("item", "value");
assertFalse(MultiMapUtils.emptyIfNull(map).isEmpty());
}
@Test
public void testIsEmptyWithEmptyMap() {
- final MultiValuedMap