[COLLECTIONS-580] Add validation to MultiValueMap#ReflectionFactory: only Collection classes are support.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1714360 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Thomas Neidhart 2015-11-14 20:24:42 +00:00
parent 7a72b1983c
commit 3eee44cf63
3 changed files with 60 additions and 1 deletions

View File

@ -29,6 +29,11 @@
ForClosure, InstantiateFactory, InstantiateTransformer, InvokerTransformer,
PrototypeCloneFactory, PrototypeSerializationFactory, WhileClosure.
</action>
<action issue="COLLECTIONS-580" dev="tn" type="fix">
Added validation when de-serializing a "MultiValueMap#ReflectionFactory":
only Collection classes are allowed, otherwise an UnsupportedOperationException
will be thrown during de-serialization.
</action>
<action issue="COLLECTIONS-576" dev="tn" type="fix" due-to="Stephan Roch">
Subclasses of MultiKey did not re-calculate their hashcode after de-serialization.
</action>

View File

@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
@ -209,6 +208,7 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
* @param value the value to remove
* @return {@code true} if the mapping was removed, {@code false} otherwise
*/
@Override
public boolean removeMapping(final Object key, final Object value) {
final Collection<V> valuesForKey = getCollection(key);
if (valuesForKey == null) {
@ -434,14 +434,18 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
}
final K key = keyIterator.next();
final Transformer<V, Entry<K, V>> transformer = new Transformer<V, Entry<K, V>>() {
@Override
public Entry<K, V> transform(final V input) {
return new Entry<K, V>() {
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return input;
}
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
@ -519,6 +523,7 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
this.iterator = values.iterator();
}
@Override
public void remove() {
iterator.remove();
if (values.isEmpty()) {
@ -526,10 +531,12 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
}
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public V next() {
return iterator.next();
}
@ -549,6 +556,7 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
this.clazz = clazz;
}
@Override
public T create() {
try {
return clazz.newInstance();
@ -556,6 +564,14 @@ public class MultiValueMap<K, V> extends AbstractMapDecorator<K, Object> impleme
throw new FunctorException("Cannot instantiate class: " + clazz, ex);
}
}
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
is.defaultReadObject();
// ensure that the de-serialized class is a Collection, COLLECTIONS-580
if (clazz != null && !Collection.class.isAssignableFrom(clazz)) {
throw new UnsupportedOperationException();
}
}
}
}

View File

@ -16,6 +16,11 @@
*/
package org.apache.commons.collections4.map;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -387,6 +392,39 @@ public class MultiValueMapTest<K, V> extends AbstractObjectTest {
assertEquals(new MultiValueMap<K, V>(), map);
}
public void testUnsafeDeSerialization() throws Exception {
MultiValueMap map1 = MultiValueMap.multiValueMap(new HashMap(), ArrayList.class);
byte[] bytes = serialize(map1);
Object result = deserialize(bytes);
assertEquals(map1, result);
MultiValueMap map2 = MultiValueMap.multiValueMap(new HashMap(), (Class) String.class);
bytes = serialize(map2);
try {
result = deserialize(bytes);
fail("unsafe clazz accepted when de-serializing MultiValueMap");
} catch (UnsupportedOperationException ex) {
// expected
}
}
private byte[] serialize(Object object) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.close();
return baos.toByteArray();
}
private Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream iis = new ObjectInputStream(bais);
return iis.readObject();
}
//-----------------------------------------------------------------------
// Manual serialization testing as this class cannot easily
// extend the AbstractTestMap