Merging from -r468106:814127 of collections_jdk5_branch - namely where this code was generified; mostly in r738956.
Also see the following revisions: ------------------------------------------------------------------------ r471189 | scolebourne | 2006-11-04 05:57:57 -0800 (Sat, 04 Nov 2006) | 1 line Remove getMap(), getOrderedMap() and getSortedMap() - use decorated() ------------------------------------------------------------------------ r468685 | scolebourne | 2006-10-28 05:30:27 -0700 (Sat, 28 Oct 2006) | 1 line COLLECTIONS-228 - MultiValueMap put and putAll do not return the correct values ------------------------------------------------------------------------ git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@815081 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
484bfbe255
commit
fd3dc7c7dd
|
@ -29,6 +29,7 @@ import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.Factory;
|
import org.apache.commons.collections.Factory;
|
||||||
import org.apache.commons.collections.FunctorException;
|
import org.apache.commons.collections.FunctorException;
|
||||||
import org.apache.commons.collections.MultiMap;
|
import org.apache.commons.collections.MultiMap;
|
||||||
|
@ -66,15 +67,15 @@ import org.apache.commons.collections.iterators.IteratorChain;
|
||||||
* @version $Revision$ $Date$
|
* @version $Revision$ $Date$
|
||||||
* @since Commons Collections 3.2
|
* @since Commons Collections 3.2
|
||||||
*/
|
*/
|
||||||
public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Serializable {
|
public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> implements MultiMap<K, V>, Serializable {
|
||||||
|
|
||||||
/** Serialization version */
|
/** Serialization version */
|
||||||
private static final long serialVersionUID = -2214159910087182007L;
|
private static final long serialVersionUID = -2214159910087182007L;
|
||||||
|
|
||||||
/** The factory for creating value collections. */
|
/** The factory for creating value collections. */
|
||||||
private final Factory collectionFactory;
|
private final Factory<? extends Collection<V>> collectionFactory;
|
||||||
/** The cached values. */
|
/** The cached values. */
|
||||||
private transient Collection valuesView;
|
private transient Collection<V> valuesView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a map which wraps the given map and
|
* Creates a map which wraps the given map and
|
||||||
|
@ -82,8 +83,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
*
|
*
|
||||||
* @param map the map to wrap
|
* @param map the map to wrap
|
||||||
*/
|
*/
|
||||||
public static MultiValueMap decorate(Map map) {
|
@SuppressWarnings("unchecked")
|
||||||
return new MultiValueMap(map, new ReflectionFactory(ArrayList.class));
|
public static <K, V> MultiValueMap<K, V> decorate(Map<K, ? super Collection<V>> map) {
|
||||||
|
return MultiValueMap.<K, V, ArrayList>decorate((Map<K, ? super Collection>) map, ArrayList.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,8 +95,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param map the map to wrap
|
* @param map the map to wrap
|
||||||
* @param collectionClass the type of the collection class
|
* @param collectionClass the type of the collection class
|
||||||
*/
|
*/
|
||||||
public static MultiValueMap decorate(Map map, Class collectionClass) {
|
public static <K, V, C extends Collection<V>> MultiValueMap<K, V> decorate(Map<K, ? super C> map, Class<C> collectionClass) {
|
||||||
return new MultiValueMap(map, new ReflectionFactory(collectionClass));
|
return new MultiValueMap<K, V>(map, new ReflectionFactory<C>(collectionClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,8 +106,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param map the map to decorate
|
* @param map the map to decorate
|
||||||
* @param collectionFactory the collection factory (must return a Collection object).
|
* @param collectionFactory the collection factory (must return a Collection object).
|
||||||
*/
|
*/
|
||||||
public static MultiValueMap decorate(Map map, Factory collectionFactory) {
|
public static <K, V, C extends Collection<V>> MultiValueMap<K, V> decorate(Map<K, ? super C> map, Factory<C> collectionFactory) {
|
||||||
return new MultiValueMap(map, collectionFactory);
|
return new MultiValueMap<K, V>(map, collectionFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
@ -113,6 +115,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* Creates a MultiValueMap based on a <code>HashMap</code> and
|
* Creates a MultiValueMap based on a <code>HashMap</code> and
|
||||||
* storing the multiple values in an <code>ArrayList</code>.
|
* storing the multiple values in an <code>ArrayList</code>.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public MultiValueMap() {
|
public MultiValueMap() {
|
||||||
this(new HashMap(), new ReflectionFactory(ArrayList.class));
|
this(new HashMap(), new ReflectionFactory(ArrayList.class));
|
||||||
}
|
}
|
||||||
|
@ -124,8 +127,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param map the map to decorate
|
* @param map the map to decorate
|
||||||
* @param collectionFactory the collection factory which must return a Collection instance
|
* @param collectionFactory the collection factory which must return a Collection instance
|
||||||
*/
|
*/
|
||||||
protected MultiValueMap(Map map, Factory collectionFactory) {
|
@SuppressWarnings("unchecked")
|
||||||
super(map);
|
protected <C extends Collection<V>> MultiValueMap(Map<K, ? super C> map, Factory<C> collectionFactory) {
|
||||||
|
super((Map<K, Object>) map);
|
||||||
if (collectionFactory == null) {
|
if (collectionFactory == null) {
|
||||||
throw new IllegalArgumentException("The factory must not be null");
|
throw new IllegalArgumentException("The factory must not be null");
|
||||||
}
|
}
|
||||||
|
@ -171,7 +175,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
// Collection coll = (Collection) keyValuePair.getValue();
|
// Collection coll = (Collection) keyValuePair.getValue();
|
||||||
// coll.clear();
|
// coll.clear();
|
||||||
// }
|
// }
|
||||||
getMap().clear();
|
decorated().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,8 +191,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param value the value to remove
|
* @param value the value to remove
|
||||||
* @return the value removed (which was passed in), null if nothing removed
|
* @return the value removed (which was passed in), null if nothing removed
|
||||||
*/
|
*/
|
||||||
public Object remove(Object key, Object value) {
|
@SuppressWarnings("unchecked")
|
||||||
Collection valuesForKey = getCollection(key);
|
public V remove(Object key, Object value) {
|
||||||
|
Collection<V> valuesForKey = getCollection(key);
|
||||||
if (valuesForKey == null) {
|
if (valuesForKey == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +204,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
if (valuesForKey.isEmpty()) {
|
if (valuesForKey.isEmpty()) {
|
||||||
remove(key);
|
remove(key);
|
||||||
}
|
}
|
||||||
return value;
|
return (V) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,17 +215,14 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param value the value to search for
|
* @param value the value to search for
|
||||||
* @return true if the map contains the value
|
* @return true if the map contains the value
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public boolean containsValue(Object value) {
|
public boolean containsValue(Object value) {
|
||||||
Set pairs = getMap().entrySet();
|
Set<Map.Entry<K, Object>> pairs = decorated().entrySet();
|
||||||
if (pairs == null) {
|
if (pairs != null) {
|
||||||
return false;
|
for (Map.Entry<K, Object> entry : pairs) {
|
||||||
}
|
if (((Collection<V>) entry.getValue()).contains(value)) {
|
||||||
Iterator pairsIterator = pairs.iterator();
|
return true;
|
||||||
while (pairsIterator.hasNext()) {
|
}
|
||||||
Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
|
|
||||||
Collection coll = (Collection) keyValuePair.getValue();
|
|
||||||
if (coll.contains(value)) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -236,19 +238,20 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param value the value to add to the collection at the key
|
* @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
|
* @return the value added if the map changed and null if the map did not change
|
||||||
*/
|
*/
|
||||||
public Object put(Object key, Object value) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object put(K key, Object value) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
Collection coll = getCollection(key);
|
Collection<V> coll = getCollection(key);
|
||||||
if (coll == null) {
|
if (coll == null) {
|
||||||
coll = createCollection(1); // might produce a non-empty collection
|
coll = createCollection(1); // might produce a non-empty collection
|
||||||
coll.add(value);
|
coll.add((V) value);
|
||||||
if (coll.size() > 0) {
|
if (coll.size() > 0) {
|
||||||
// only add if non-zero size to maintain class state
|
// only add if non-zero size to maintain class state
|
||||||
getMap().put(key, coll);
|
decorated().put(key, coll);
|
||||||
result = true; // map definitely changed
|
result = true; // map definitely changed
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = coll.add(value);
|
result = coll.add((V) value);
|
||||||
}
|
}
|
||||||
return (result ? value : null);
|
return (result ? value : null);
|
||||||
}
|
}
|
||||||
|
@ -264,17 +267,15 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
*
|
*
|
||||||
* @param map the map to copy (either a normal or multi map)
|
* @param map the map to copy (either a normal or multi map)
|
||||||
*/
|
*/
|
||||||
public void putAll(Map map) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public void putAll(Map<? extends K, ?> map) {
|
||||||
if (map instanceof MultiMap) {
|
if (map instanceof MultiMap) {
|
||||||
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
|
for (Map.Entry<? extends K, Object> entry : ((MultiMap<? extends K, V>) map).entrySet()) {
|
||||||
Map.Entry entry = (Map.Entry) it.next();
|
putAll(entry.getKey(), (Collection<V>) entry.getValue());
|
||||||
Collection coll = (Collection) entry.getValue();
|
|
||||||
putAll(entry.getKey(), coll);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
|
for (Map.Entry<? extends K, ?> entry : map.entrySet()) {
|
||||||
Map.Entry entry = (Map.Entry) it.next();
|
put(entry.getKey(), (V) entry.getValue());
|
||||||
put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,11 +287,10 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
*
|
*
|
||||||
* @return a collection view of the values contained in this map
|
* @return a collection view of the values contained in this map
|
||||||
*/
|
*/
|
||||||
public Collection values() {
|
@SuppressWarnings("unchecked")
|
||||||
if (valuesView == null) {
|
public Collection<Object> values() {
|
||||||
valuesView = new Values();
|
Collection<V> vs = valuesView;
|
||||||
}
|
return (Collection<Object>) (vs != null ? vs : (valuesView = new Values()));
|
||||||
return valuesView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -300,7 +300,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @return true if the map contains the value
|
* @return true if the map contains the value
|
||||||
*/
|
*/
|
||||||
public boolean containsValue(Object key, Object value) {
|
public boolean containsValue(Object key, Object value) {
|
||||||
Collection coll = getCollection(key);
|
Collection<V> coll = getCollection(key);
|
||||||
if (coll == null) {
|
if (coll == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -314,8 +314,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param key the key to retrieve
|
* @param key the key to retrieve
|
||||||
* @return the collection mapped to the key, null if no mapping
|
* @return the collection mapped to the key, null if no mapping
|
||||||
*/
|
*/
|
||||||
public Collection getCollection(Object key) {
|
@SuppressWarnings("unchecked")
|
||||||
return (Collection) getMap().get(key);
|
public Collection<V> getCollection(Object key) {
|
||||||
|
return (Collection<V>) decorated().get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -325,7 +326,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @return the size of the collection at the key, zero if key not in map
|
* @return the size of the collection at the key, zero if key not in map
|
||||||
*/
|
*/
|
||||||
public int size(Object key) {
|
public int size(Object key) {
|
||||||
Collection coll = getCollection(key);
|
Collection<V> coll = getCollection(key);
|
||||||
if (coll == null) {
|
if (coll == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -340,18 +341,18 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @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, null ignored
|
||||||
* @return true if this map changed
|
* @return true if this map changed
|
||||||
*/
|
*/
|
||||||
public boolean putAll(Object key, Collection values) {
|
public boolean putAll(K key, Collection<V> values) {
|
||||||
if (values == null || values.size() == 0) {
|
if (values == null || values.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
Collection coll = getCollection(key);
|
Collection<V> coll = getCollection(key);
|
||||||
if (coll == null) {
|
if (coll == null) {
|
||||||
coll = createCollection(values.size()); // might produce a non-empty collection
|
coll = createCollection(values.size()); // might produce a non-empty collection
|
||||||
coll.addAll(values);
|
coll.addAll(values);
|
||||||
if (coll.size() > 0) {
|
if (coll.size() > 0) {
|
||||||
// only add if non-zero size to maintain class state
|
// only add if non-zero size to maintain class state
|
||||||
getMap().put(key, coll);
|
decorated().put(key, coll);
|
||||||
result = true; // map definitely changed
|
result = true; // map definitely changed
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -366,12 +367,11 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param key the key to get an iterator for
|
* @param key the key to get an iterator for
|
||||||
* @return the iterator of the collection at the key, empty iterator if key not in map
|
* @return the iterator of the collection at the key, empty iterator if key not in map
|
||||||
*/
|
*/
|
||||||
public Iterator iterator(Object key) {
|
public Iterator<V> iterator(Object key) {
|
||||||
if (!containsKey(key)) {
|
if (!containsKey(key)) {
|
||||||
return EmptyIterator.INSTANCE;
|
return EmptyIterator.<V>getInstance();
|
||||||
} else {
|
|
||||||
return new ValuesIterator(key);
|
|
||||||
}
|
}
|
||||||
|
return new ValuesIterator(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -381,10 +381,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
*/
|
*/
|
||||||
public int totalSize() {
|
public int totalSize() {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
Collection values = getMap().values();
|
for (Object v : decorated().values()) {
|
||||||
for (Iterator it = values.iterator(); it.hasNext();) {
|
total += CollectionUtils.size(v);
|
||||||
Collection coll = (Collection) it.next();
|
|
||||||
total += coll.size();
|
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
@ -399,18 +397,18 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
* @param size the collection size that is about to be added
|
* @param size the collection size that is about to be added
|
||||||
* @return the new collection
|
* @return the new collection
|
||||||
*/
|
*/
|
||||||
protected Collection createCollection(int size) {
|
protected Collection<V> createCollection(int size) {
|
||||||
return (Collection) collectionFactory.create();
|
return collectionFactory.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Inner class that provides the values view.
|
* Inner class that provides the values view.
|
||||||
*/
|
*/
|
||||||
private class Values extends AbstractCollection {
|
private class Values extends AbstractCollection<V> {
|
||||||
public Iterator iterator() {
|
public Iterator<V> iterator() {
|
||||||
final IteratorChain chain = new IteratorChain();
|
final IteratorChain<V> chain = new IteratorChain<V>();
|
||||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
for (Iterator<K> it = keySet().iterator(); it.hasNext();) {
|
||||||
chain.addIterator(new ValuesIterator(it.next()));
|
chain.addIterator(new ValuesIterator(it.next()));
|
||||||
}
|
}
|
||||||
return chain;
|
return chain;
|
||||||
|
@ -428,10 +426,10 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
/**
|
/**
|
||||||
* Inner class that provides the values iterator.
|
* Inner class that provides the values iterator.
|
||||||
*/
|
*/
|
||||||
private class ValuesIterator implements Iterator {
|
private class ValuesIterator implements Iterator<V> {
|
||||||
private final Object key;
|
private final Object key;
|
||||||
private final Collection values;
|
private final Collection<V> values;
|
||||||
private final Iterator iterator;
|
private final Iterator<V> iterator;
|
||||||
|
|
||||||
public ValuesIterator(Object key) {
|
public ValuesIterator(Object key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
@ -450,7 +448,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
return iterator.hasNext();
|
return iterator.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object next() {
|
public V next() {
|
||||||
return iterator.next();
|
return iterator.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,14 +456,18 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap, Ser
|
||||||
/**
|
/**
|
||||||
* Inner class that provides a simple reflection factory.
|
* Inner class that provides a simple reflection factory.
|
||||||
*/
|
*/
|
||||||
private static class ReflectionFactory implements Factory, Serializable {
|
private static class ReflectionFactory<T extends Collection<?>> implements Factory<T>, Serializable {
|
||||||
private final Class clazz;
|
|
||||||
|
|
||||||
public ReflectionFactory(Class clazz) {
|
/** Serialization version */
|
||||||
|
private static final long serialVersionUID = 2986114157496788874L;
|
||||||
|
|
||||||
|
private final Class<T> clazz;
|
||||||
|
|
||||||
|
public ReflectionFactory(Class<T> clazz) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object create() {
|
public T create() {
|
||||||
try {
|
try {
|
||||||
return clazz.newInstance();
|
return clazz.newInstance();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
Loading…
Reference in New Issue