Author: tn Date: Sat Nov 14 20:24:42 2015 New Revision: 1714360 URL: http://svn.apache.org/viewvc?rev=1714360&view=rev Log: [COLLECTIONS-580] Add validation to MultiValueMap#ReflectionFactory: only Collection classes are support.
Modified: commons/proper/collections/trunk/src/changes/changes.xml commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/map/MultiValueMap.java commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/map/MultiValueMapTest.java Modified: commons/proper/collections/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1714360&r1=1714359&r2=1714360&view=diff ============================================================================== --- commons/proper/collections/trunk/src/changes/changes.xml (original) +++ commons/proper/collections/trunk/src/changes/changes.xml Sat Nov 14 20:24:42 2015 @@ -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> Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/map/MultiValueMap.java URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/map/MultiValueMap.java?rev=1714360&r1=1714359&r2=1714360&view=diff ============================================================================== --- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/map/MultiValueMap.java (original) +++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/map/MultiValueMap.java Sat Nov 14 20:24:42 2015 @@ -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 * @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 } 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 this.iterator = values.iterator(); } + @Override public void remove() { iterator.remove(); if (values.isEmpty()) { @@ -526,10 +531,12 @@ public class MultiValueMap<K, V> extends } } + @Override public boolean hasNext() { return iterator.hasNext(); } + @Override public V next() { return iterator.next(); } @@ -549,6 +556,7 @@ public class MultiValueMap<K, V> extends this.clazz = clazz; } + @Override public T create() { try { return clazz.newInstance(); @@ -556,6 +564,14 @@ public class MultiValueMap<K, V> extends 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(); + } + } } } Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/map/MultiValueMapTest.java URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/map/MultiValueMapTest.java?rev=1714360&r1=1714359&r2=1714360&view=diff ============================================================================== --- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/map/MultiValueMapTest.java (original) +++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/map/MultiValueMapTest.java Sat Nov 14 20:24:42 2015 @@ -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> ext 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