diff --git a/src/main/java/org/apache/commons/collections4/ListValuedMap.java b/src/main/java/org/apache/commons/collections4/ListValuedMap.java index 765e55096..a62d177ef 100644 --- a/src/main/java/org/apache/commons/collections4/ListValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/ListValuedMap.java @@ -21,10 +21,10 @@ import java.util.List; /** * Defines a map that holds a list of values against each key. *

- * A ListValuedMap is a Map with slightly different semantics: + * A {@code ListValuedMap} is a Map with slightly different semantics: *

* * @since 4.1 @@ -40,12 +40,13 @@ public interface ListValuedMap extends MultiValuedMap { * returned list will update the underlying {@code ListValuedMap} and * vice-versa. * - * @param key the key to retrieve - * @return the List of values, implementations should return an - * empty list for no mapping + * @param key the key to retrieve + * @return the {@code List} of values, implementations should return an + * empty {@code List} for no mapping * @throws ClassCastException if the key is of an invalid type * @throws NullPointerException if the key is null and null keys are invalid */ + @Override List get(Object key); /** @@ -55,13 +56,14 @@ public interface ListValuedMap extends MultiValuedMap { * propagated to this list-valued map. In case no mapping was stored for the * specified key, an empty, unmodifiable list will be returned. * - * @param key the key to remove values from - * @return the List of values removed, implementations - * typically return an empty, unmodifiable List for no mapping found + * @param key the key to remove values from + * @return the {@code List} of values removed, implementations + * typically return an empty, unmodifiable {@code List} for no mapping found * @throws UnsupportedOperationException if the map is unmodifiable * @throws ClassCastException if the key is of an invalid type * @throws NullPointerException if the key is null and null keys are invalid */ + @Override List remove(Object key); } diff --git a/src/main/java/org/apache/commons/collections4/MultiValuedMap.java b/src/main/java/org/apache/commons/collections4/MultiValuedMap.java index fb2095f38..66c7da085 100644 --- a/src/main/java/org/apache/commons/collections4/MultiValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/MultiValuedMap.java @@ -24,10 +24,10 @@ import java.util.Set; /** * Defines a map that holds a collection of values against each key. *

- * A MultiValuedMap is a Map with slightly different semantics: + * A {@code 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.
  • + *
  • Putting a value into the map will add the value to a {@link Collection} at that key.
  • + *
  • Getting a value will return a {@link Collection}, holding all the values put to that key.
  • *
*

* For example: @@ -67,52 +67,49 @@ public interface MultiValuedMap { /** * Returns {@code true} if this map contains a mapping for the specified - * key. More formally, returns {@code true} if and only if this map - * contains a mapping for a key {@code k} such that - * {@code (key==null ? k==null : key.equals(k))}. (There can be at most one - * such mapping.) + * key. More formally, returns {@code true} if and only if this map contains + * a mapping for a key {@code k} such that {@code (key==null ? k==null : key.equals(k))}. + * (There can be at most one such mapping.) * - * @param key key whose presence in this map is to be tested - * @return {@code true} if this map contains a mapping for the specified key + * @param key key whose presence in this map is to be tested + * @return true if this map contains a mapping for the specified key * @throws ClassCastException if the key is of an inappropriate type for this map (optional) * @throws NullPointerException if the specified key is null and this map - * does not permit null keys (optional) + * does not permit null keys (optional) */ boolean containsKey(Object key); /** * Checks whether the map contains at least one mapping for the specified value. * - * @param value the value to search for + * @param value the value to search for * @return true if the map contains the value * @throws ClassCastException if the type of the specified value is not compatible - * with the used collection (optional) + * with the used collection (optional) * @throws NullPointerException if the value is null and null values are not supported - * by the used collection types (optional) + * by the used collection types (optional) */ boolean containsValue(Object value); /** * Checks whether the map contains a mapping for the specified key and value. * - * @param key the key to search for - * @param value the value to search for + * @param key the key to search for + * @param value the value to search for * @return true if the map contains the value */ boolean containsMapping(Object key, Object value); /** - * Returns a view collection of the values associated with the specified - * key. + * Returns a view collection of the values associated with the specified key. *

- * This method will return an empty collection if - * {@link #containsKey(Object)} returns {@code false}. Changes to the - * returned collection will update the underlying {@code MultiValuedMap} and - * vice-versa. + * This method will return an empty collection if {@link #containsKey(Object)} + * returns {@code false}. Changes to the returned collection will update the underlying + * {@code MultiValuedMap} and vice-versa. * - * @param key the key to retrieve - * @return the Collection of values, implementations should - * return an empty collection for no mapping + * @param key the key to retrieve + * @return the {@code Collection} of values, implementations should + * return an empty collection for no mapping * @throws ClassCastException if the key is of an invalid type (optional) * @throws NullPointerException if the key is null and null keys are invalid (optional) */ @@ -123,7 +120,7 @@ public interface MultiValuedMap { /** * Adds a key-value mapping to this multi-valued map. *

- * Unlike a normal Map the previous value is not replaced. + * Unlike a normal {@code Map} the previous value is not replaced. * Instead the new value is added to the collection stored against the key. * Depending on the collection type used, duplicate key-value mappings may * be allowed. @@ -131,31 +128,35 @@ public interface MultiValuedMap { * The method will return {@code true} if the size of the multi-valued map * has been increased because of this operation. * - * @param key the key to store against - * @param value the value to add to the collection at the key - * @return {@code true} if the map changed as a result of this put operation, or - * {@code false} if the map already contained the key-value mapping and the - * collection type does not allow duplicate values, e.g. when using a Set + * @param key the key to store against + * @param value the value to add to the collection at the key + * @return true if the map changed as a result of this put operation, or false + * if the map already contained the key-value mapping and the collection + * type does not allow duplicate values, e.g. when using a Set * @throws UnsupportedOperationException if the put operation is not supported by - * this multi-valued map, e.g. if it is unmodifiable + * this multi-valued map, e.g. if it is unmodifiable * @throws ClassCastException if the key or value is of an invalid type (optional) * @throws NullPointerException if the key or value is null and null is invalid (optional) * @throws IllegalArgumentException if some aspect of the specified key or value prevents - * it from being stored in this multi-valued map + * it from being stored in this multi-valued map */ boolean put(K key, V value); /** * Adds a mapping to the specified key for all values contained in the given Iterable. * - * @param key the key to store against - * @param values the values to add to the collection at the key, null ignored - * @return {@code true} if the map changed as a result of this operation + * @param key the key to store against + * @param values the values to add to the collection at the key, may not be null + * @return true if the map changed as a result of this operation + * @throws NullPointerException if the specified iterable is null, or if this map + * does not permit null keys or values, and the specified key or values contain + * null (optional) */ boolean putAll(K key, Iterable values); /** - * Copies all mappings from the specified map to this multi-valued map (optional operation). + * Copies all mappings from the specified map to this multi-valued map + * (optional operation). *

* The effect of this call is equivalent to that of calling * {@link #put(Object,Object) put(k, v)} on this map once for each mapping @@ -164,41 +165,42 @@ public interface MultiValuedMap { * The behavior of this operation is undefined if the specified map is modified * while the operation is in progress. * - * @param m mappings to be stored in this map + * @param map mappings to be stored in this map, may not be null * @throws UnsupportedOperationException if the {@code putAll} operation is - * not supported by this map + * not supported by this map * @throws ClassCastException if the class of a key or value in the - * specified map prevents it from being stored in this map (optional) + * specified map prevents it from being stored in this map (optional) * @throws NullPointerException if the specified map is null, or if this map - * does not permit null keys or values, and the specified map - * contains null keys or values (optional) + * does not permit null keys or values, and the specified map + * contains null keys or values (optional) * @throws IllegalArgumentException if some property of a key or value in - * the specified map prevents it from being stored in this map + * the specified map prevents it from being stored in this map */ - void putAll(Map m); + void putAll(Map map); /** - * Copies all mappings from the specified map to this multi-valued map (optional operation). + * Copies all mappings from the specified map to this multi-valued map + * (optional operation). *

- * The effect of this call is equivalent to that of - * calling {@link #put(Object,Object) put(k, v)} on this map once for each + * The effect of this call is equivalent to that of calling + * {@link #put(Object,Object) put(k, v)} on this map once for each * mapping from key {@code k} to value {@code v} in the specified map. *

* The behavior of this operation is undefined if the specified map is modified * while the operation is in progress. * - * @param m mappings to be stored in this map + * @param map mappings to be stored in this map, may not be null * @throws UnsupportedOperationException if the {@code putAll} operation is - * not supported by this map + * not supported by this map * @throws ClassCastException if the class of a key or value in the - * specified map prevents it from being stored in this map (optional) + * specified map prevents it from being stored in this map (optional) * @throws NullPointerException if the specified map is null, or if this map - * does not permit null keys or values, and the specified map - * contains null keys or values (optional) + * does not permit null keys or values, and the specified map + * contains null keys or values (optional) * @throws IllegalArgumentException if some property of a key or value in - * the specified map prevents it from being stored in this map + * the specified map prevents it from being stored in this map */ - void putAll(MultiValuedMap m); + void putAll(MultiValuedMap map); /** * Removes all values associated with the specified key. @@ -207,7 +209,7 @@ public interface MultiValuedMap { * to this multi-valued map. In case no mapping was stored for the specified * key, an empty, unmodifiable collection will be returned. * - * @param key the key to remove values from + * @param key the key to remove values from * @return the values that were removed * @throws UnsupportedOperationException if the map is unmodifiable * @throws ClassCastException if the key is of an invalid type (optional) @@ -224,9 +226,9 @@ public interface MultiValuedMap { * If the last value for a key is removed, implementations typically return * an empty collection from a subsequent get(Object). * - * @param key the key to remove from - * @param item the item to remove - * @return {@code true} if the mapping was removed, {@code false} otherwise + * @param key the key to remove from + * @param item the item to remove + * @return true if the mapping was removed, false otherwise * @throws UnsupportedOperationException if the map is unmodifiable * @throws ClassCastException if the key or value is of an invalid type (optional) * @throws NullPointerException if the key or value is null and null is invalid (optional) @@ -255,16 +257,17 @@ public interface MultiValuedMap { Collection> entries(); /** - * Returns a {@link Bag} view of the keys contained in this multi-valued map. + * Returns a {@link MultiSet} view of the keys contained in this multi-valued map. *

- * The {@link Bag#getCount(Object)} method of the returned bag will give the - * same result a calling {@code get(Object).size()} for the same key. + * The {@link MultiSet#getCount(Object)} method of the returned multiset will give + * the same result a calling {@code get(Object).size()} for the same key. *

- * This bag is backed by the map, so any changes in the map are reflected in the bag. + * This multiset is backed by the map, so any changes in the map are reflected in + * the multiset. * - * @return a bag view of the keys contained in this map + * @return a multiset view of the keys contained in this map */ - Bag keys(); + MultiSet keys(); /** * Returns a {@link Set} view of the keys contained in this multi-valued map. @@ -290,7 +293,7 @@ public interface MultiValuedMap { * Implementations typically return a collection containing the combination * of values from all keys. * - * @return a collection view of the values contained in this map + * @return a collection view of the values contained in this multi-valued map */ Collection values(); @@ -298,7 +301,7 @@ public interface MultiValuedMap { * Returns a {@link Map} view of this MultiValuedMap with a Collection as * its value. The Collection holds all the values mapped to that key. * - * @return a Map view of the mappings in this MultiValuedMap + * @return a map view of the mappings in this multi-valued map */ Map> asMap(); diff --git a/src/main/java/org/apache/commons/collections4/SetValuedMap.java b/src/main/java/org/apache/commons/collections4/SetValuedMap.java index 29edf3cdc..3e21702fe 100644 --- a/src/main/java/org/apache/commons/collections4/SetValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/SetValuedMap.java @@ -21,12 +21,10 @@ import java.util.Set; /** * Defines a map that holds a set of values against each key. *

- * A SetValuedMap is a Map with slightly different semantics: + * A {@code SetValuedMap} is a Map with slightly different semantics: *

    - *
  • Putting a value into the map will add the value to a Set at - * that key.
  • - *
  • Getting a value will return a Set, holding all the values - * put to that key.
  • + *
  • Putting a value into the map will add the value to a {@link Set} at that key.
  • + *
  • Getting a value will return a {@link Set}, holding all the values put to that key.
  • *
* * @since 4.1 @@ -37,16 +35,17 @@ public interface SetValuedMap extends MultiValuedMap { /** * Gets the set of values associated with the specified key. *

- * Implementations typically return an empty Set if no values + * Implementations typically return an empty {@code Set} if no values * have been mapped to the key. *

* * @param key the key to retrieve - * @return the Set of values, implementations should return an - * empty Set for no mapping + * @return the {@code Set} of values, implementations should return an + * empty {@code Set} for no mapping * @throws ClassCastException if the key is of an invalid type * @throws NullPointerException if the key is null and null keys are invalid */ + @Override Set get(Object key); /** @@ -57,12 +56,12 @@ public interface SetValuedMap extends MultiValuedMap { * specified key, an empty, unmodifiable set will be returned. * * @param key the key to remove values from - * @return the Set of values removed, implementations should - * return null for no mapping found, but may return an - * empty collection + * @return the {@code Set} of values removed, implementations should + * return null for no mapping found, but may return an empty collection * @throws UnsupportedOperationException if the map is unmodifiable * @throws ClassCastException if the key is of an invalid type * @throws NullPointerException if the key is null and null keys are invalid */ + @Override Set remove(Object key); } 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 d6a11e9f1..75f6d614f 100644 --- a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMap.java @@ -26,14 +26,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.apache.commons.collections4.Bag; 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.bag.HashBag; import org.apache.commons.collections4.functors.InstantiateFactory; import org.apache.commons.collections4.iterators.EmptyMapIterator; import org.apache.commons.collections4.iterators.IteratorChain; @@ -65,8 +64,8 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** The EntryValues view */ private transient EntryValues entryValuesView; - /** The KeyBag view */ - private transient KeysBag keysBagView; + /** The KeyMultiSet view */ + private transient KeysMultiSet keysMultiSetView; /** The map used to store the data */ private final Map> map; @@ -125,6 +124,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public boolean containsKey(Object key) { return getMap().containsKey(key); } @@ -132,6 +132,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public boolean containsValue(final Object value) { final Set>> pairs = getMap().entrySet(); if (pairs != null) { @@ -147,6 +148,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public boolean containsMapping(Object key, Object value) { final Collection col = getMap().get(key); if (col == null) { @@ -158,6 +160,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public Collection> entries() { return entryValuesView != null ? entryValuesView : (entryValuesView = new EntryValues()); } @@ -171,6 +174,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * Collection for no mapping * @throws ClassCastException if the key is of an invalid type */ + @Override public Collection get(Object key) { return new WrappedCollection(key); } @@ -185,6 +189,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * empty, unmodifiable collection for no mapping found. * @throws ClassCastException if the key is of an invalid type */ + @Override public Collection remove(Object key) { return CollectionUtils.emptyIfNull(getMap().remove(key)); } @@ -202,6 +207,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * @param item the item to remove * @return {@code true} if the mapping was removed, {@code false} otherwise */ + @Override public boolean removeMapping(K key, V item) { boolean result = false; final Collection col = getMap().get(key); @@ -221,6 +227,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public boolean isEmpty() { return getMap().isEmpty(); } @@ -228,6 +235,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public Set keySet() { return getMap().keySet(); } @@ -235,6 +243,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public int size() { int size = 0; for (Collection col : getMap().values()) { @@ -250,6 +259,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * * @return a collection view of the values contained in this map */ + @Override public Collection values() { final Collection vs = valuesView; return vs != null ? vs : (valuesView = new Values()); @@ -258,6 +268,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public void clear() { getMap().clear(); } @@ -272,6 +283,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * @param value the value to add to the collection at the key * @return the value added if the map changed and null if the map did not change */ + @Override public boolean put(K key, V value) { boolean result = false; Collection coll = getMap().get(key); @@ -299,10 +311,11 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * * @param map mappings to be stored in this map */ + @Override public void putAll(final Map map) { if (map != null) { for (final Map.Entry entry : map.entrySet()) { - put((K) entry.getKey(), (V) entry.getValue()); + put(entry.getKey(), entry.getValue()); } } } @@ -317,33 +330,35 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * * @param map mappings to be stored in this map */ - @SuppressWarnings("unchecked") + @Override public void putAll(MultiValuedMap map) { if (map != null) { for (final K key : map.keySet()) { - putAll(key, (Collection) map.get(key)); + putAll(key, map.get(key)); } } } /** - * Returns a {@link Bag} view of the key mapping contained in this map. + * Returns a {@link MultiSet} view of the key mapping contained in this map. *

- * Returns a Bag of keys with its values count as the count of the Bag. This - * bag is backed by the map, so any changes in the map is reflected here. - * Any method which modifies this bag like {@code add}, {@code remove}, - * {@code Iterator.remove} etc throws - * UnsupportedOperationException + * Returns a MultiSet of keys with its values count as the count of the MultiSet. + * This multiset is backed by the map, so any changes in the map is reflected here. + * Any method which modifies this multiset like {@code add}, {@code remove}, + * {@link Iterator#remove()} etc throws {@code UnsupportedOperationException}. * * @return a bag view of the key mapping contained in this map */ - public Bag keys() { - return keysBagView != null ? keysBagView : (keysBagView = new KeysBag()); + @Override + public MultiSet keys() { + return keysMultiSetView != null ? keysMultiSetView + : (keysMultiSetView = new KeysMultiSet()); } /** * {@inheritDoc} */ + @Override public Map> asMap() { return getMap(); } @@ -352,15 +367,20 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria * Adds Iterable values to the collection associated with the specified key. * * @param key the key to store against - * @param values the values to add to the collection at the key, null - * ignored + * @param values the values to add to the collection at the key, may not be null * @return true if this map changed + * @throws NullPointerException if values is null */ + @Override public boolean putAll(final K key, final Iterable values) { - if (values == null || values.iterator() == null || !values.iterator().hasNext()) { + if (values == null) { + throw new NullPointerException("Values must not be null."); + } + + Iterator it = values.iterator(); + if (!it.hasNext()) { return false; } - Iterator it = values.iterator(); boolean result = false; Collection coll = getMap().get(key); if (coll == null) { @@ -389,6 +409,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria /** * {@inheritDoc} */ + @Override public MapIterator mapIterator() { if (size() == 0) { return EmptyMapIterator.emptyMapIterator(); @@ -477,6 +498,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return getMap().get(key); } + @Override @SuppressWarnings("unchecked") public boolean add(V value) { final Collection col = getMapping(); @@ -486,6 +508,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.add(value); } + @Override @SuppressWarnings("unchecked") public boolean addAll(Collection c) { final Collection col = getMapping(); @@ -495,6 +518,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.addAll(c); } + @Override public void clear() { final Collection col = getMapping(); if (col != null) { @@ -503,15 +527,17 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria } } + @Override @SuppressWarnings("unchecked") public Iterator iterator() { final Collection col = getMapping(); if (col == null) { - return (Iterator) IteratorUtils.EMPTY_ITERATOR; + return IteratorUtils.EMPTY_ITERATOR; } return new ValuesIterator(key); } + @Override public int size() { final Collection col = getMapping(); if (col == null) { @@ -520,6 +546,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.size(); } + @Override public boolean contains(Object o) { final Collection col = getMapping(); if (col == null) { @@ -528,6 +555,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.contains(o); } + @Override public boolean containsAll(Collection o) { final Collection col = getMapping(); if (col == null) { @@ -536,6 +564,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.containsAll(o); } + @Override public boolean isEmpty() { final Collection col = getMapping(); if (col == null) { @@ -544,6 +573,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.isEmpty(); } + @Override public boolean remove(Object item) { final Collection col = getMapping(); if (col == null) { @@ -557,6 +587,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return result; } + @Override public boolean removeAll(Collection c) { final Collection col = getMapping(); if (col == null) { @@ -570,6 +601,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return result; } + @Override public boolean retainAll(Collection c) { final Collection col = getMapping(); if (col == null) { @@ -583,6 +615,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return result; } + @Override public Object[] toArray() { final Collection col = getMapping(); if (col == null) { @@ -591,6 +624,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return col.toArray(); } + @Override @SuppressWarnings("unchecked") public T[] toArray(T[] a) { final Collection col = getMapping(); @@ -612,26 +646,31 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria } /** - * Inner class that provides a Bag keys view + * Inner class that provides a MultiSet keys view */ - private class KeysBag implements Bag { + private class KeysMultiSet implements MultiSet { + @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + @Override public void clear() { throw new UnsupportedOperationException(); } + @Override public boolean contains(Object o) { return getMap().containsKey(o); } + @Override public boolean isEmpty() { return getMap().isEmpty(); } + @Override public Object[] toArray() { final Object[] result = new Object[size()]; int i = 0; @@ -645,6 +684,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return result; } + @Override public T[] toArray(T[] array) { final int size = size(); if (array.length < size) { @@ -672,6 +712,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return array; } + @Override public int getCount(Object object) { int count = 0; Collection col = AbstractMultiValuedMap.this.getMap().get(object); @@ -681,56 +722,69 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return count; } + @Override + public int setCount(K object, int count) { + throw new UnsupportedOperationException(); + } + + @Override public boolean add(K object) { throw new UnsupportedOperationException(); } - public boolean add(K object, int nCopies) { + @Override + public int add(K object, int nCopies) { throw new UnsupportedOperationException(); } + @Override public boolean remove(Object object) { throw new UnsupportedOperationException(); } - public boolean remove(Object object, int nCopies) { + @Override + public int remove(Object object, int nCopies) { throw new UnsupportedOperationException(); } + @Override public Set uniqueSet() { return UnmodifiableSet.unmodifiableSet(keySet()); } + @Override + public Set> entrySet() { + // TODO: implement + throw new UnsupportedOperationException(); + } + + @Override public int size() { return AbstractMultiValuedMap.this.size(); } + @Override public boolean containsAll(Collection coll) { - if (coll instanceof Bag) { - return containsAll((Bag) coll); - } - return containsAll(new HashBag(coll)); - } - - private boolean containsAll(final Bag other) { - final Iterator it = other.uniqueSet().iterator(); - while (it.hasNext()) { - final Object current = it.next(); - if (getCount(current) < other.getCount(current)) { + final Iterator e = coll.iterator(); + while (e.hasNext()) { + if(!contains(e.next())) { return false; } } return true; } + @Override public boolean removeAll(Collection coll) { throw new UnsupportedOperationException(); } + @Override public boolean retainAll(Collection coll) { throw new UnsupportedOperationException(); } + @Override public Iterator iterator() { return new LazyIteratorChain() { @@ -745,10 +799,12 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria final Iterator colIterator = getMap().get(key).iterator(); Iterator nextIt = new Iterator() { + @Override public boolean hasNext() { return colIterator.hasNext(); } + @Override public K next() { colIterator.next();// Increment the iterator // The earlier statement would throw @@ -756,6 +812,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return key; } + @Override public void remove() { throw new UnsupportedOperationException(); } @@ -787,6 +844,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria final K key = keyIterator.next(); final Transformer> entryTransformer = new Transformer>() { + @Override public Entry transform(final V input) { return new MultiValuedMapEntry(key, input); } @@ -833,15 +891,18 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria this.it = AbstractMultiValuedMap.this.entries().iterator(); } + @Override public boolean hasNext() { return it.hasNext(); } + @Override public K next() { current = it.next(); return current.getKey(); } + @Override public K getKey() { if (current == null) { throw new IllegalStateException(); @@ -849,6 +910,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return current.getKey(); } + @Override public V getValue() { if (current == null) { throw new IllegalStateException(); @@ -856,10 +918,12 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria return current.getValue(); } + @Override public void remove() { it.remove(); } + @Override public V setValue(V value) { if (current == null) { throw new IllegalStateException(); @@ -907,6 +971,7 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria this.iterator = values.iterator(); } + @Override public void remove() { iterator.remove(); if (values.isEmpty()) { @@ -914,10 +979,12 @@ public class AbstractMultiValuedMap implements MultiValuedMap, Seria } } + @Override public boolean hasNext() { return iterator.hasNext(); } + @Override public V next() { return iterator.next(); } 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 5d9b17c67..196a9441d 100644 --- a/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java +++ b/src/main/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapDecorator.java @@ -22,8 +22,8 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.apache.commons.collections4.Bag; import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; import org.apache.commons.collections4.MultiValuedMap; /** @@ -65,78 +65,97 @@ public class AbstractMultiValuedMapDecorator return map; } + @Override public int size() { return decorated().size(); } + @Override public boolean isEmpty() { return decorated().isEmpty(); } + @Override public boolean containsKey(Object key) { return decorated().containsKey(key); } + @Override public boolean containsValue(Object value) { return decorated().containsValue(value); } + @Override public boolean containsMapping(Object key, Object value) { return decorated().containsMapping(key, value); } + @Override public Collection get(Object key) { return decorated().get(key); } + @Override public Collection remove(Object key) { return decorated().remove(key); } + @Override public boolean removeMapping(K key, V item) { return decorated().removeMapping(key, item); } + @Override public void clear() { decorated().clear(); } + @Override public boolean put(K key, V value) { return decorated().put(key, value); } + @Override public Set keySet() { return decorated().keySet(); } + @Override public Collection> entries() { return decorated().entries(); } - public Bag keys() { + @Override + public MultiSet keys() { return decorated().keys(); } + @Override public Collection values() { return decorated().values(); } + @Override public Map> asMap() { return decorated().asMap(); } + @Override public boolean putAll(K key, Iterable values) { return decorated().putAll(key, values); } + @Override public void putAll(Map m) { decorated().putAll(m); } + @Override public void putAll(MultiValuedMap m) { decorated().putAll(m); } + @Override public MapIterator mapIterator() { return decorated().mapIterator(); } 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 a8ec707c3..fb7905c25 100644 --- a/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMap.java @@ -43,8 +43,10 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor /** Serialization Version */ private static final long serialVersionUID = -1254147899086470720L; + /** The key transformer */ private final Transformer keyTransformer; + /** The value transformer */ private final Transformer valueTransformer; /** @@ -54,15 +56,13 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor * NOT transformed. Contrast this with * {@link #transformedMap(MultiValuedMap, Transformer, Transformer)}. * - * @param the key type - * @param the value type - * @param map the MultiValuedMap to decorate, must not be null - * @param keyTransformer the transformer to use for key conversion, null - * means no transformation - * @param valueTransformer the transformer to use for value conversion, null - * means no transformation + * @param the key type + * @param the value type + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion * @return a new transformed MultiValuedMap - * @throws IllegalArgumentException if map is null + * @throws NullPointerException if map is null */ public static TransformedMultiValuedMap transformingMap(final MultiValuedMap map, final Transformer keyTransformer, @@ -78,15 +78,13 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor * be transformed by this method. Contrast this with * {@link #transformingMap(MultiValuedMap, Transformer, Transformer)}. * - * @param the key type - * @param the value type - * @param map the MultiValuedMap to decorate, must not be null - * @param keyTransformer the transformer to use for key conversion, null - * means no transformation - * @param valueTransformer the transformer to use for value conversion, null - * means no transformation + * @param the key type + * @param the value type + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion * @return a new transformed MultiValuedMap - * @throws IllegalArgumentException if map is null + * @throws NullPointerException if map is null */ public static TransformedMultiValuedMap transformedMap(final MultiValuedMap map, final Transformer keyTransformer, @@ -109,12 +107,10 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor * If there are any elements already in the collection being decorated, they * are NOT transformed. * - * @param map the MultiValuedMap to decorate, must not be null - * @param keyTransformer the transformer to use for key conversion, null - * means no conversion - * @param valueTransformer the transformer to use for value conversion, null - * means no conversion - * @throws IllegalArgumentException if map is null + * @param map the MultiValuedMap to decorate, may not be null + * @param keyTransformer the transformer to use for key conversion, null means no conversion + * @param valueTransformer the transformer to use for value conversion, null means no conversion + * @throws NullPointerException if map is null */ protected TransformedMultiValuedMap(MultiValuedMap map, Transformer keyTransformer, Transformer valueTransformer) { @@ -128,7 +124,7 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor *

* The transformer itself may throw an exception if necessary. * - * @param object the object to transform + * @param object the object to transform * @return the transformed object */ protected K transformKey(final K object) { @@ -143,7 +139,7 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor *

* The transformer itself may throw an exception if necessary. * - * @param object the object to transform + * @param object the object to transform * @return the transformed object */ protected V transformValue(final V object) { @@ -158,7 +154,7 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor *

* The transformer itself may throw an exception if necessary. * - * @param map the map to transform + * @param map the map to transform * @return the transformed object */ @SuppressWarnings("unchecked") @@ -179,11 +175,12 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor *

* The transformer itself may throw an exception if necessary. * - * @param map the MultiValuedMap to transform + * @param map the MultiValuedMap to transform * @return the transformed object */ @SuppressWarnings("unchecked") - protected MultiValuedMap transformMultiValuedMap(final MultiValuedMap map) { + protected MultiValuedMap transformMultiValuedMap( + final MultiValuedMap map) { if (map.isEmpty()) { return (MultiValuedMap) map; } @@ -205,12 +202,16 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor @Override @SuppressWarnings("unchecked") public boolean putAll(K key, Iterable values) { - if (values == null || values.iterator() == null || !values.iterator().hasNext()) { + if (values == null) { + throw new NullPointerException("Values must not be null."); + } + + Iterator it = (Iterator) values.iterator(); + if (!it.hasNext()) { return false; } K transformedKey = transformKey(key); List transformedValues = new LinkedList(); - Iterator it = (Iterator) values.iterator(); while (it.hasNext()) { transformedValues.add(transformValue(it.next())); } @@ -219,17 +220,11 @@ public class TransformedMultiValuedMap extends AbstractMultiValuedMapDecor @Override public void putAll(Map m) { - if (m == null) { - return; - } decorated().putAll(transformMap(m)); } @Override public void putAll(MultiValuedMap m) { - if (m == null) { - return; - } decorated().putAll(transformMultiValuedMap(m)); } diff --git a/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java b/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java index cbd9457ec..d2c028c2d 100644 --- a/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java +++ b/src/main/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMap.java @@ -21,14 +21,14 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.apache.commons.collections4.Bag; import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.Unmodifiable; -import org.apache.commons.collections4.bag.UnmodifiableBag; import org.apache.commons.collections4.collection.UnmodifiableCollection; import org.apache.commons.collections4.iterators.UnmodifiableMapIterator; import org.apache.commons.collections4.map.UnmodifiableMap; +import org.apache.commons.collections4.multiset.UnmodifiableMultiSet; import org.apache.commons.collections4.set.UnmodifiableSet; /** @@ -53,11 +53,11 @@ public class UnmodifiableMultiValuedMap *

* If the map passed in is already unmodifiable, it is returned. * - * @param the type of key elements - * @param the type of value elements - * @param map the map to decorate, must not be null + * @param the type of key elements + * @param the type of value elements + * @param map the map to decorate, may not be null * @return an unmodifiable MultiValuedMap - * @throws IllegalArgumentException if map is null + * @throws NullPointerException if map is null */ @SuppressWarnings("unchecked") public static UnmodifiableMultiValuedMap unmodifiableMultiValuedMap( @@ -71,8 +71,8 @@ public class UnmodifiableMultiValuedMap /** * Constructor that wraps (not copies). * - * @param map the MultiValuedMap to decorate, must not be null - * @throws IllegalArgumentException if the map is null + * @param map the MultiValuedMap to decorate, may not be null + * @throws NullPointerException if the map is null */ @SuppressWarnings("unchecked") private UnmodifiableMultiValuedMap(final MultiValuedMap map) { @@ -106,22 +106,22 @@ public class UnmodifiableMultiValuedMap @Override public Set keySet() { - return UnmodifiableSet.unmodifiableSet(decorated().keySet()); + return UnmodifiableSet.unmodifiableSet(decorated().keySet()); } @Override public Collection> entries() { - return UnmodifiableCollection.>unmodifiableCollection(decorated().entries()); + return UnmodifiableCollection.unmodifiableCollection(decorated().entries()); } @Override - public Bag keys() { - return UnmodifiableBag.unmodifiableBag(decorated().keys()); + public MultiSet keys() { + return UnmodifiableMultiSet.unmodifiableMultiSet(decorated().keys()); } @Override public Collection values() { - return UnmodifiableCollection.unmodifiableCollection(decorated().values()); + return UnmodifiableCollection.unmodifiableCollection(decorated().values()); } @Override 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 a884a8edc..ace5aa153 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 @@ -21,6 +21,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 *
*

* The following decorators are provided in the package: diff --git a/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java b/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java index 49084a91c..47bcc3252 100644 --- a/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java +++ b/src/test/java/org/apache/commons/collections4/multimap/AbstractMultiValuedMapTest.java @@ -31,12 +31,13 @@ import org.apache.commons.collections4.Bag; import org.apache.commons.collections4.BulkTest; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.bag.AbstractBagTest; -import org.apache.commons.collections4.bag.CollectionBag; import org.apache.commons.collections4.bag.HashBag; import org.apache.commons.collections4.collection.AbstractCollectionTest; import org.apache.commons.collections4.map.AbstractMapTest; +import org.apache.commons.collections4.multiset.AbstractMultiSetTest; import org.apache.commons.collections4.set.AbstractSetTest; /** @@ -507,14 +508,14 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes @SuppressWarnings("unchecked") public void testContainsValue_Key() { final MultiValuedMap map = makeFullMap(); - assertEquals(true, map.containsMapping("one", (V) "uno")); - assertEquals(false, map.containsMapping("two", (V) "2")); + assertEquals(true, map.containsMapping("one", "uno")); + assertEquals(false, map.containsMapping("two", "2")); if (!isAddSupported()) { return; } map.put((K) "A", (V) "AA"); - assertEquals(true, map.containsMapping("A", (V) "AA")); - assertEquals(false, map.containsMapping("A", (V) "AB")); + assertEquals(true, map.containsMapping("A", "AA")); + assertEquals(false, map.containsMapping("A", "AB")); } @SuppressWarnings("unchecked") @@ -576,29 +577,35 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes assertEquals(true, map.putAll((K) "A", coll)); assertEquals(3, map.get("A").size()); - assertEquals(true, map.containsMapping("A", (V) "X")); - assertEquals(true, map.containsMapping("A", (V) "Y")); - assertEquals(true, map.containsMapping("A", (V) "Z")); + assertEquals(true, map.containsMapping("A", "X")); + assertEquals(true, map.containsMapping("A", "Y")); + assertEquals(true, map.containsMapping("A", "Z")); + + try { + map.putAll((K) "A", null); + fail("expecting NullPointerException"); + } catch (NullPointerException npe) { + // expected + } - assertEquals(false, map.putAll((K) "A", null)); assertEquals(3, map.get("A").size()); - assertEquals(true, map.containsMapping("A", (V) "X")); - assertEquals(true, map.containsMapping("A", (V) "Y")); - assertEquals(true, map.containsMapping("A", (V) "Z")); + assertEquals(true, map.containsMapping("A", "X")); + assertEquals(true, map.containsMapping("A", "Y")); + assertEquals(true, map.containsMapping("A", "Z")); assertEquals(false, map.putAll((K) "A", new ArrayList())); assertEquals(3, map.get("A").size()); - assertEquals(true, map.containsMapping("A", (V) "X")); - assertEquals(true, map.containsMapping("A", (V) "Y")); - assertEquals(true, map.containsMapping("A", (V) "Z")); + assertEquals(true, map.containsMapping("A", "X")); + assertEquals(true, map.containsMapping("A", "Y")); + assertEquals(true, map.containsMapping("A", "Z")); coll = (Collection) Arrays.asList("M"); assertEquals(true, map.putAll((K) "A", coll)); assertEquals(4, map.get("A").size()); - assertEquals(true, map.containsMapping("A", (V) "X")); - assertEquals(true, map.containsMapping("A", (V) "Y")); - assertEquals(true, map.containsMapping("A", (V) "Z")); - assertEquals(true, map.containsMapping("A", (V) "M")); + assertEquals(true, map.containsMapping("A", "X")); + assertEquals(true, map.containsMapping("A", "Y")); + assertEquals(true, map.containsMapping("A", "Z")); + assertEquals(true, map.containsMapping("A", "M")); } @SuppressWarnings("unchecked") @@ -618,13 +625,13 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes //assertEquals(new MultiValuedHashMap(), map); } - public void testKeysBag() { + public void testKeysMultiSet() { MultiValuedMap map = makeFullMap(); - Bag keyBag = map.keys(); - assertEquals(2, keyBag.getCount("one")); - assertEquals(2, keyBag.getCount("two")); - assertEquals(2, keyBag.getCount("three")); - assertEquals(6, keyBag.size()); + MultiSet keyMultiSet = map.keys(); + assertEquals(2, keyMultiSet.getCount("one")); + assertEquals(2, keyMultiSet.getCount("two")); + assertEquals(2, keyMultiSet.getCount("three")); + assertEquals(6, keyMultiSet.size()); } public void testKeysBagIterator() { @@ -644,9 +651,9 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes @SuppressWarnings("unchecked") public void testKeysBagContainsAll() { MultiValuedMap map = makeFullMap(); - Bag keyBag = map.keys(); + MultiSet keyMultiSet = map.keys(); Collection col = (Collection) Arrays.asList("one", "two", "three", "one", "two", "three"); - assertTrue(keyBag.containsAll(col)); + assertTrue(keyMultiSet.containsAll(col)); } public void testAsMapGet() { @@ -750,7 +757,7 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes } public void testFullMapCompatibility() throws Exception { - final MultiValuedMap map = (MultiValuedMap) makeFullMap(); + final MultiValuedMap map = makeFullMap(); final MultiValuedMap map2 = (MultiValuedMap) readExternalFormFromDisk(getCanonicalFullCollectionName(map)); assertEquals("Map is the right size", map.size(), map2.size()); @@ -998,7 +1005,7 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes return new TestMultiValuedMapKeys(); } - public class TestMultiValuedMapKeys extends AbstractBagTest { + public class TestMultiValuedMapKeys extends AbstractMultiSetTest { public TestMultiValuedMapKeys() { super(""); @@ -1010,12 +1017,12 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes } @Override - public Bag makeObject() { + public MultiSet makeObject() { return AbstractMultiValuedMapTest.this.makeObject().keys(); } @Override - public Bag makeFullCollection() { + public MultiSet makeFullCollection() { return AbstractMultiValuedMapTest.this.makeFullMap().keys(); } @@ -1042,16 +1049,14 @@ public abstract class AbstractMultiValuedMapTest extends AbstractObjectTes @Override public void resetFull() { AbstractMultiValuedMapTest.this.resetFull(); - // wrapping with CollectionBag as otherwise the Collection tests - // would fail - setCollection(CollectionBag.collectionBag(AbstractMultiValuedMapTest.this.getMap().keys())); + setCollection(AbstractMultiValuedMapTest.this.getMap().keys()); TestMultiValuedMapKeys.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().keys()); } @Override public void resetEmpty() { AbstractMultiValuedMapTest.this.resetEmpty(); - setCollection(CollectionBag.collectionBag(AbstractMultiValuedMapTest.this.getMap().keys())); + setCollection(AbstractMultiValuedMapTest.this.getMap().keys()); TestMultiValuedMapKeys.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().keys()); } diff --git a/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java b/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java index 36c795a2b..c56973299 100644 --- a/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java +++ b/src/test/java/org/apache/commons/collections4/multimap/UnmodifiableMultiValuedMapTest.java @@ -25,9 +25,9 @@ import java.util.Set; import junit.framework.Test; -import org.apache.commons.collections4.Bag; import org.apache.commons.collections4.BulkTest; import org.apache.commons.collections4.MapIterator; +import org.apache.commons.collections4.MultiSet; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.Unmodifiable; @@ -47,10 +47,12 @@ public class UnmodifiableMultiValuedMapTest extends AbstractMultiValuedMap return BulkTest.makeSuite(UnmodifiableMultiValuedMapTest.class); } + @Override public boolean isAddSupported() { return false; } + @Override public boolean isRemoveSupported() { return false; } @@ -60,6 +62,7 @@ public class UnmodifiableMultiValuedMapTest extends AbstractMultiValuedMap return UnmodifiableMultiValuedMap. unmodifiableMultiValuedMap(new MultiValuedHashMap()); } + @Override protected MultiValuedMap makeFullMap() { final MultiValuedMap map = new MultiValuedHashMap(); addSampleMappings(map); @@ -229,7 +232,7 @@ public class UnmodifiableMultiValuedMapTest extends AbstractMultiValuedMap @SuppressWarnings("unchecked") public void testUnmodifiableKeys() { resetFull(); - Bag keys = getMap().keys(); + MultiSet keys = getMap().keys(); try { keys.add((K) "four"); fail();