Continue review of MultiValuedMap interface and implementations: code style and formatting, use NullPointerException for null arguments, use MultiSet instead of Bag.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1684983 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Thomas Neidhart 2015-06-11 22:07:08 +00:00
parent fb08d55cbe
commit 4f5a854b28
10 changed files with 302 additions and 207 deletions

View File

@ -21,10 +21,10 @@ import java.util.List;
/**
* Defines a map that holds a list of values against each key.
* <p>
* A <code>ListValuedMap</code> is a Map with slightly different semantics:
* A {@code ListValuedMap} is a Map with slightly different semantics:
* <ul>
* <li>Putting a value into the map will add the value to a Collection at that key.</li>
* <li>Getting a value will return a Collection, holding all the values put to that key.</li>
* <li>Putting a value into the map will add the value to a {@link List} at that key.</li>
* <li>Getting a value will return a {@link List}, holding all the values put to that key.</li>
* </ul>
*
* @since 4.1
@ -40,12 +40,13 @@ public interface ListValuedMap<K, V> extends MultiValuedMap<K, V> {
* returned list will update the underlying {@code ListValuedMap} and
* vice-versa.
*
* @param key the key to retrieve
* @return the <code>List</code> 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<V> get(Object key);
/**
@ -55,13 +56,14 @@ public interface ListValuedMap<K, V> extends MultiValuedMap<K, V> {
* 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 <code>List</code> 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<V> remove(Object key);
}

View File

@ -24,10 +24,10 @@ import java.util.Set;
/**
* Defines a map that holds a collection of values against each key.
* <p>
* A <code>MultiValuedMap</code> is a Map with slightly different semantics:
* A {@code MultiValuedMap} is a Map with slightly different semantics:
* <ul>
* <li>Putting a value into the map will add the value to a Collection at that key.</li>
* <li>Getting a value will return a Collection, holding all the values put to that key.</li>
* <li>Putting a value into the map will add the value to a {@link Collection} at that key.</li>
* <li>Getting a value will return a {@link Collection}, holding all the values put to that key.</li>
* </ul>
* <p>
* For example:
@ -67,52 +67,49 @@ public interface MultiValuedMap<K, V> {
/**
* 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.
* <p>
* This method will return an <b>empty</b> 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 <b>empty</b> 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 <code>Collection</code> 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<K, V> {
/**
* Adds a key-value mapping to this multi-valued map.
* <p>
* Unlike a normal <code>Map</code> 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<K, V> {
* 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<? extends V> 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).
* <p>
* 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<K, V> {
* 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<? extends K, ? extends V> m);
void putAll(Map<? extends K, ? extends V> 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).
* <p>
* 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.
* <p>
* 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<? extends K, ? extends V> m);
void putAll(MultiValuedMap<? extends K, ? extends V> map);
/**
* Removes all values associated with the specified key.
@ -207,7 +209,7 @@ public interface MultiValuedMap<K, V> {
* 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<K, V> {
* If the last value for a key is removed, implementations typically return
* an empty collection from a subsequent <code>get(Object)</code>.
*
* @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<K, V> {
Collection<Entry<K, V>> 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.
* <p>
* 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.
* <p>
* 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<K> keys();
MultiSet<K> keys();
/**
* Returns a {@link Set} view of the keys contained in this multi-valued map.
@ -290,7 +293,7 @@ public interface MultiValuedMap<K, V> {
* 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<V> values();
@ -298,7 +301,7 @@ public interface MultiValuedMap<K, V> {
* 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<K, Collection<V>> asMap();

View File

@ -21,12 +21,10 @@ import java.util.Set;
/**
* Defines a map that holds a set of values against each key.
* <p>
* A <code>SetValuedMap</code> is a Map with slightly different semantics:
* A {@code SetValuedMap} is a Map with slightly different semantics:
* <ul>
* <li>Putting a value into the map will add the value to a <code>Set</code> at
* that key.</li>
* <li>Getting a value will return a <code>Set</code>, holding all the values
* put to that key.</li>
* <li>Putting a value into the map will add the value to a {@link Set} at that key.</li>
* <li>Getting a value will return a {@link Set}, holding all the values put to that key.</li>
* </ul>
*
* @since 4.1
@ -37,16 +35,17 @@ public interface SetValuedMap<K, V> extends MultiValuedMap<K, V> {
/**
* Gets the set of values associated with the specified key.
* <p>
* Implementations typically return an empty <code>Set</code> if no values
* Implementations typically return an empty {@code Set} if no values
* have been mapped to the key.
* <p>
*
* @param key the key to retrieve
* @return the <code>Set</code> 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<V> get(Object key);
/**
@ -57,12 +56,12 @@ public interface SetValuedMap<K, V> extends MultiValuedMap<K, V> {
* specified key, an empty, unmodifiable set will be returned.
*
* @param key the key to remove values from
* @return the <code>Set</code> of values removed, implementations should
* return <code>null</code> 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<V> remove(Object key);
}

View File

@ -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<K, V> implements MultiValuedMap<K, V>, 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<K, Collection<V>> map;
@ -125,6 +124,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public boolean containsKey(Object key) {
return getMap().containsKey(key);
}
@ -132,6 +132,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public boolean containsValue(final Object value) {
final Set<Map.Entry<K, Collection<V>>> pairs = getMap().entrySet();
if (pairs != null) {
@ -147,6 +148,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public boolean containsMapping(Object key, Object value) {
final Collection<V> col = getMap().get(key);
if (col == null) {
@ -158,6 +160,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public Collection<Entry<K, V>> entries() {
return entryValuesView != null ? entryValuesView : (entryValuesView = new EntryValues());
}
@ -171,6 +174,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
* <code>Collection</code> for no mapping
* @throws ClassCastException if the key is of an invalid type
*/
@Override
public Collection<V> get(Object key) {
return new WrappedCollection(key);
}
@ -185,6 +189,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
* empty, unmodifiable collection for no mapping found.
* @throws ClassCastException if the key is of an invalid type
*/
@Override
public Collection<V> remove(Object key) {
return CollectionUtils.emptyIfNull(getMap().remove(key));
}
@ -202,6 +207,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<V> col = getMap().get(key);
@ -221,6 +227,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return getMap().isEmpty();
}
@ -228,6 +235,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public Set<K> keySet() {
return getMap().keySet();
}
@ -235,6 +243,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public int size() {
int size = 0;
for (Collection<V> col : getMap().values()) {
@ -250,6 +259,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
*
* @return a collection view of the values contained in this map
*/
@Override
public Collection<V> values() {
final Collection<V> vs = valuesView;
return vs != null ? vs : (valuesView = new Values());
@ -258,6 +268,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public void clear() {
getMap().clear();
}
@ -272,6 +283,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<V> coll = getMap().get(key);
@ -299,10 +311,11 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
*
* @param map mappings to be stored in this map
*/
@Override
public void putAll(final Map<? extends K, ? extends V> map) {
if (map != null) {
for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
put((K) entry.getKey(), (V) entry.getValue());
put(entry.getKey(), entry.getValue());
}
}
}
@ -317,33 +330,35 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
*
* @param map mappings to be stored in this map
*/
@SuppressWarnings("unchecked")
@Override
public void putAll(MultiValuedMap<? extends K, ? extends V> map) {
if (map != null) {
for (final K key : map.keySet()) {
putAll(key, (Collection<V>) 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.
* <p>
* 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
* <code>UnsupportedOperationException</code>
* 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<K> keys() {
return keysBagView != null ? keysBagView : (keysBagView = new KeysBag());
@Override
public MultiSet<K> keys() {
return keysMultiSetView != null ? keysMultiSetView
: (keysMultiSetView = new KeysMultiSet());
}
/**
* {@inheritDoc}
*/
@Override
public Map<K, Collection<V>> asMap() {
return getMap();
}
@ -352,15 +367,20 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<? extends V> values) {
if (values == null || values.iterator() == null || !values.iterator().hasNext()) {
if (values == null) {
throw new NullPointerException("Values must not be null.");
}
Iterator<? extends V> it = values.iterator();
if (!it.hasNext()) {
return false;
}
Iterator<? extends V> it = values.iterator();
boolean result = false;
Collection<V> coll = getMap().get(key);
if (coll == null) {
@ -389,6 +409,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
/**
* {@inheritDoc}
*/
@Override
public MapIterator<K, V> mapIterator() {
if (size() == 0) {
return EmptyMapIterator.<K, V>emptyMapIterator();
@ -477,6 +498,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return getMap().get(key);
}
@Override
@SuppressWarnings("unchecked")
public boolean add(V value) {
final Collection<V> col = getMapping();
@ -486,6 +508,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.add(value);
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection<? extends V> c) {
final Collection<V> col = getMapping();
@ -495,6 +518,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.addAll(c);
}
@Override
public void clear() {
final Collection<V> col = getMapping();
if (col != null) {
@ -503,15 +527,17 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
}
}
@Override
@SuppressWarnings("unchecked")
public Iterator<V> iterator() {
final Collection<V> col = getMapping();
if (col == null) {
return (Iterator<V>) IteratorUtils.EMPTY_ITERATOR;
return IteratorUtils.EMPTY_ITERATOR;
}
return new ValuesIterator(key);
}
@Override
public int size() {
final Collection<V> col = getMapping();
if (col == null) {
@ -520,6 +546,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.size();
}
@Override
public boolean contains(Object o) {
final Collection<V> col = getMapping();
if (col == null) {
@ -528,6 +555,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.contains(o);
}
@Override
public boolean containsAll(Collection<?> o) {
final Collection<V> col = getMapping();
if (col == null) {
@ -536,6 +564,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.containsAll(o);
}
@Override
public boolean isEmpty() {
final Collection<V> col = getMapping();
if (col == null) {
@ -544,6 +573,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.isEmpty();
}
@Override
public boolean remove(Object item) {
final Collection<V> col = getMapping();
if (col == null) {
@ -557,6 +587,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return result;
}
@Override
public boolean removeAll(Collection<?> c) {
final Collection<V> col = getMapping();
if (col == null) {
@ -570,6 +601,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return result;
}
@Override
public boolean retainAll(Collection<?> c) {
final Collection<V> col = getMapping();
if (col == null) {
@ -583,6 +615,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return result;
}
@Override
public Object[] toArray() {
final Collection<V> col = getMapping();
if (col == null) {
@ -591,6 +624,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return col.toArray();
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
final Collection<V> col = getMapping();
@ -612,26 +646,31 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
}
/**
* Inner class that provides a Bag<K> keys view
* Inner class that provides a MultiSet<K> keys view
*/
private class KeysBag implements Bag<K> {
private class KeysMultiSet implements MultiSet<K> {
@Override
public boolean addAll(Collection<? extends K> 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<K, V> implements MultiValuedMap<K, V>, Seria
return result;
}
@Override
public <T> T[] toArray(T[] array) {
final int size = size();
if (array.length < size) {
@ -672,6 +712,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
return array;
}
@Override
public int getCount(Object object) {
int count = 0;
Collection<V> col = AbstractMultiValuedMap.this.getMap().get(object);
@ -681,56 +722,69 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<K> uniqueSet() {
return UnmodifiableSet.<K>unmodifiableSet(keySet());
}
@Override
public Set<MultiSet.Entry<K>> 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<Object>(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<K> iterator() {
return new LazyIteratorChain<K>() {
@ -745,10 +799,12 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
final Iterator<V> colIterator = getMap().get(key).iterator();
Iterator<K> nextIt = new Iterator<K>() {
@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<K, V> implements MultiValuedMap<K, V>, Seria
return key;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@ -787,6 +844,7 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
final K key = keyIterator.next();
final Transformer<V, Entry<K, V>> entryTransformer = new Transformer<V, Entry<K, V>>() {
@Override
public Entry<K, V> transform(final V input) {
return new MultiValuedMapEntry(key, input);
}
@ -833,15 +891,18 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<K, V> implements MultiValuedMap<K, V>, Seria
return current.getKey();
}
@Override
public V getValue() {
if (current == null) {
throw new IllegalStateException();
@ -856,10 +918,12 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, 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<K, V> implements MultiValuedMap<K, V>, Seria
this.iterator = values.iterator();
}
@Override
public void remove() {
iterator.remove();
if (values.isEmpty()) {
@ -914,10 +979,12 @@ public class AbstractMultiValuedMap<K, V> implements MultiValuedMap<K, V>, Seria
}
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public V next() {
return iterator.next();
}

View File

@ -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<K, V>
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<V> get(Object key) {
return decorated().get(key);
}
@Override
public Collection<V> 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<K> keySet() {
return decorated().keySet();
}
@Override
public Collection<Entry<K, V>> entries() {
return decorated().entries();
}
public Bag<K> keys() {
@Override
public MultiSet<K> keys() {
return decorated().keys();
}
@Override
public Collection<V> values() {
return decorated().values();
}
@Override
public Map<K, Collection<V>> asMap() {
return decorated().asMap();
}
@Override
public boolean putAll(K key, Iterable<? extends V> values) {
return decorated().putAll(key, values);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
decorated().putAll(m);
}
@Override
public void putAll(MultiValuedMap<? extends K, ? extends V> m) {
decorated().putAll(m);
}
@Override
public MapIterator<K, V> mapIterator() {
return decorated().mapIterator();
}

View File

@ -43,8 +43,10 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
/** Serialization Version */
private static final long serialVersionUID = -1254147899086470720L;
/** The key transformer */
private final Transformer<? super K, ? extends K> keyTransformer;
/** The value transformer */
private final Transformer<? super V, ? extends V> valueTransformer;
/**
@ -54,15 +56,13 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
* NOT transformed. Contrast this with
* {@link #transformedMap(MultiValuedMap, Transformer, Transformer)}.
*
* @param <K> the key type
* @param <V> 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 <K> the key type
* @param <V> 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 <K, V> TransformedMultiValuedMap<K, V> transformingMap(final MultiValuedMap<K, V> map,
final Transformer<? super K, ? extends K> keyTransformer,
@ -78,15 +78,13 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
* be transformed by this method. Contrast this with
* {@link #transformingMap(MultiValuedMap, Transformer, Transformer)}.
*
* @param <K> the key type
* @param <V> 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 <K> the key type
* @param <V> 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 <K, V> TransformedMultiValuedMap<K, V> transformedMap(final MultiValuedMap<K, V> map,
final Transformer<? super K, ? extends K> keyTransformer,
@ -109,12 +107,10 @@ public class TransformedMultiValuedMap<K, V> 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<K, V> map,
Transformer<? super K, ? extends K> keyTransformer, Transformer<? super V, ? extends V> valueTransformer) {
@ -128,7 +124,7 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
* <p>
* 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<K, V> extends AbstractMultiValuedMapDecor
* <p>
* 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<K, V> extends AbstractMultiValuedMapDecor
* <p>
* 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<K, V> extends AbstractMultiValuedMapDecor
* <p>
* 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<K, V> transformMultiValuedMap(final MultiValuedMap<? extends K, ? extends V> map) {
protected MultiValuedMap<K, V> transformMultiValuedMap(
final MultiValuedMap<? extends K, ? extends V> map) {
if (map.isEmpty()) {
return (MultiValuedMap<K, V>) map;
}
@ -205,12 +202,16 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
@Override
@SuppressWarnings("unchecked")
public boolean putAll(K key, Iterable<? extends V> values) {
if (values == null || values.iterator() == null || !values.iterator().hasNext()) {
if (values == null) {
throw new NullPointerException("Values must not be null.");
}
Iterator<V> it = (Iterator<V>) values.iterator();
if (!it.hasNext()) {
return false;
}
K transformedKey = transformKey(key);
List<V> transformedValues = new LinkedList<V>();
Iterator<V> it = (Iterator<V>) values.iterator();
while (it.hasNext()) {
transformedValues.add(transformValue(it.next()));
}
@ -219,17 +220,11 @@ public class TransformedMultiValuedMap<K, V> extends AbstractMultiValuedMapDecor
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (m == null) {
return;
}
decorated().putAll(transformMap(m));
}
@Override
public void putAll(MultiValuedMap<? extends K, ? extends V> m) {
if (m == null) {
return;
}
decorated().putAll(transformMultiValuedMap(m));
}

View File

@ -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<K, V>
* <p>
* If the map passed in is already unmodifiable, it is returned.
*
* @param <K> the type of key elements
* @param <V> the type of value elements
* @param map the map to decorate, must not be null
* @param <K> the type of key elements
* @param <V> 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 <K, V> UnmodifiableMultiValuedMap<K, V> unmodifiableMultiValuedMap(
@ -71,8 +71,8 @@ public class UnmodifiableMultiValuedMap<K, V>
/**
* 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<? extends K, ? extends V> map) {
@ -106,22 +106,22 @@ public class UnmodifiableMultiValuedMap<K, V>
@Override
public Set<K> keySet() {
return UnmodifiableSet.<K>unmodifiableSet(decorated().keySet());
return UnmodifiableSet.unmodifiableSet(decorated().keySet());
}
@Override
public Collection<Entry<K, V>> entries() {
return UnmodifiableCollection.<Entry<K, V>>unmodifiableCollection(decorated().entries());
return UnmodifiableCollection.unmodifiableCollection(decorated().entries());
}
@Override
public Bag<K> keys() {
return UnmodifiableBag.<K>unmodifiableBag(decorated().keys());
public MultiSet<K> keys() {
return UnmodifiableMultiSet.unmodifiableMultiSet(decorated().keys());
}
@Override
public Collection<V> values() {
return UnmodifiableCollection.<V>unmodifiableCollection(decorated().values());
return UnmodifiableCollection.unmodifiableCollection(decorated().values());
}
@Override

View File

@ -21,6 +21,8 @@
* The following implementations are provided in the package:
* <ul>
* <li>MultiValuedHashMap - implementation that uses a HashMap to store the data
* <li>ListValuedHashMap - implementation of a ListValuedMap using a HashMap as data store
* <li>SetValuedHashMap - implementation of a SetValuedMap using a HashMap as data store
* </ul>
* <p>
* The following decorators are provided in the package:

View File

@ -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<K, V> extends AbstractObjectTes
@SuppressWarnings("unchecked")
public void testContainsValue_Key() {
final MultiValuedMap<K, V> 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<K, V> 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<V>()));
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<V>) 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<K, V> extends AbstractObjectTes
//assertEquals(new MultiValuedHashMap<K, V>(), map);
}
public void testKeysBag() {
public void testKeysMultiSet() {
MultiValuedMap<K, V> map = makeFullMap();
Bag<K> keyBag = map.keys();
assertEquals(2, keyBag.getCount("one"));
assertEquals(2, keyBag.getCount("two"));
assertEquals(2, keyBag.getCount("three"));
assertEquals(6, keyBag.size());
MultiSet<K> 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<K, V> extends AbstractObjectTes
@SuppressWarnings("unchecked")
public void testKeysBagContainsAll() {
MultiValuedMap<K, V> map = makeFullMap();
Bag<K> keyBag = map.keys();
MultiSet<K> keyMultiSet = map.keys();
Collection<K> col = (Collection<K>) 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<K, V> 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<K, V> extends AbstractObjectTes
return new TestMultiValuedMapKeys();
}
public class TestMultiValuedMapKeys extends AbstractBagTest<K> {
public class TestMultiValuedMapKeys extends AbstractMultiSetTest<K> {
public TestMultiValuedMapKeys() {
super("");
@ -1010,12 +1017,12 @@ public abstract class AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
}
@Override
public Bag<K> makeObject() {
public MultiSet<K> makeObject() {
return AbstractMultiValuedMapTest.this.makeObject().keys();
}
@Override
public Bag<K> makeFullCollection() {
public MultiSet<K> makeFullCollection() {
return AbstractMultiValuedMapTest.this.makeFullMap().keys();
}
@ -1042,16 +1049,14 @@ public abstract class AbstractMultiValuedMapTest<K, V> extends AbstractObjectTes
@Override
public void resetFull() {
AbstractMultiValuedMapTest.this.resetFull();
// wrapping with CollectionBag as otherwise the Collection tests
// would fail
setCollection(CollectionBag.<K>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.<K>collectionBag(AbstractMultiValuedMapTest.this.getMap().keys()));
setCollection(AbstractMultiValuedMapTest.this.getMap().keys());
TestMultiValuedMapKeys.this.setConfirmed(AbstractMultiValuedMapTest.this.getConfirmed().keys());
}

View File

@ -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<K, V> 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<K, V> extends AbstractMultiValuedMap
return UnmodifiableMultiValuedMap.<K, V> unmodifiableMultiValuedMap(new MultiValuedHashMap<K, V>());
}
@Override
protected MultiValuedMap<K, V> makeFullMap() {
final MultiValuedMap<K, V> map = new MultiValuedHashMap<K, V>();
addSampleMappings(map);
@ -229,7 +232,7 @@ public class UnmodifiableMultiValuedMapTest<K, V> extends AbstractMultiValuedMap
@SuppressWarnings("unchecked")
public void testUnmodifiableKeys() {
resetFull();
Bag<K> keys = getMap().keys();
MultiSet<K> keys = getMap().keys();
try {
keys.add((K) "four");
fail();