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:
parent
fb08d55cbe
commit
4f5a854b28
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue