This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git


The following commit(s) were added to refs/heads/master by this push:
     new 54dded70b [COLLECTIONS-881] MultiMapUtils.getXXX ensure safe copy 
(#669)
54dded70b is described below

commit 54dded70be00b36586f5846941bf65d352da6949
Author: Suhyeon Park <[email protected]>
AuthorDate: Mon Jun 15 06:00:39 2026 +0900

    [COLLECTIONS-881] MultiMapUtils.getXXX ensure safe copy (#669)
---
 .../apache/commons/collections4/MultiMapUtils.java | 18 ++------
 .../commons/collections4/MultiMapUtilsTest.java    | 48 +++++++++++++++++++++-
 2 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java 
b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
index 226f1dc52..11806413d 100644
--- a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
+++ b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
@@ -102,14 +102,11 @@ public class MultiMapUtils {
      * @param <V> the value type
      * @param map  the {@link MultiValuedMap} to use
      * @param key  the key to look up
-     * @return the Collection in the {@link MultiValuedMap} as Bag, or null if 
input map is null
+     * @return a new Bag containing the values from the {@link 
MultiValuedMap}, or null if input map is null
      */
     public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, 
final K key) {
         if (map != null) {
             final Collection<V> col = map.get(key);
-            if (col instanceof Bag) {
-                return (Bag<V>) col;
-            }
             return new HashBag<>(col);
         }
         return null;
@@ -122,22 +119,16 @@ public class MultiMapUtils {
      * @param <V> the value type
      * @param map  the {@link MultiValuedMap} to use
      * @param key  the key to look up
-     * @return the Collection in the {@link MultiValuedMap} as List, or null 
if input map is null
+     * @return a new List containing the values from the {@link 
MultiValuedMap}, or null if input map is null
      */
     public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> 
map, final K key) {
         if (map != null) {
             final Collection<V> col = map.get(key);
-            if (col instanceof List) {
-                return (List<V>) col;
-            }
             return new ArrayList<>(col);
         }
         return null;
     }
 
-    // TODO: review the getValuesAsXXX methods - depending on the actual 
MultiValuedMap type, changes
-    // to the returned collection might update the backing map. This should be 
clarified and/or prevented.
-
     /**
      * Gets a Set from {@code MultiValuedMap} in a null-safe manner.
      *
@@ -145,14 +136,11 @@ public class MultiMapUtils {
      * @param <V> the value type
      * @param map  the {@link MultiValuedMap} to use
      * @param key  the key to look up
-     * @return the Collection in the {@link MultiValuedMap} as Set, or null if 
input map is null
+     * @return a new Set containing the values from the {@link 
MultiValuedMap}, or null if input map is null
      */
     public static <K, V> Set<V> getValuesAsSet(final MultiValuedMap<K, V> map, 
final K key) {
         if (map != null) {
             final Collection<V> col = map.get(key);
-            if (col instanceof Set) {
-                return (Set<V>) col;
-            }
             return new HashSet<>(col);
         }
         return null;
diff --git 
a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java 
b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
index 7ff98ba07..4bb3528d0 100644
--- a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
@@ -16,6 +16,10 @@
  */
 package org.apache.commons.collections4;
 
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.easymock.EasyMock.createMock;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -28,6 +32,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.commons.collections4.bag.HashBag;
 import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
 import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
 import 
org.apache.commons.collections4.multimap.LinkedHashSetValuedLinkedHashMap;
@@ -105,7 +110,7 @@ class MultiMapUtilsTest {
 
     @Test
     void testGetValuesAsSet() {
-        assertNull(MultiMapUtils.getValuesAsList(null, "key1"));
+        assertNull(MultiMapUtils.getValuesAsSet(null, "key1"));
 
         final String[] values = { "v1", "v2", "v3" };
         final MultiValuedMap<String, String> map = new 
ArrayListValuedHashMap<>();
@@ -118,6 +123,47 @@ class MultiMapUtilsTest {
         assertEquals(new HashSet<>(Arrays.asList(values)), set);
     }
 
+    @Test
+    void testGetValuesAsBagIsSafeCopy() {
+        final String[] values = { "v1", "v2", "v3" };
+        final MultiValuedMap<String, String> mockMap = 
createMock(MultiValuedMap.class);
+        final Bag<String> bagToReturn = new HashBag<>();
+        bagToReturn.addAll(Arrays.asList(values));
+        expect(mockMap.get("key1")).andReturn(bagToReturn);
+        replay(mockMap);
+
+        final Bag<String> bag = MultiMapUtils.getValuesAsBag(mockMap, "key1");
+        bag.add("v4");
+        assertFalse(bagToReturn.contains("v4"));
+        verify(mockMap);
+    }
+
+    @Test
+    void testGetValuesAsListIsSafeCopy() {
+        final String[] values = { "v1", "v2", "v3" };
+        final MultiValuedMap<String, String> map = new 
ArrayListValuedHashMap<>();
+        for (final String val : values) {
+            map.put("key1", val);
+        }
+
+        final List<String> list = MultiMapUtils.getValuesAsList(map, "key1");
+        list.add("v4");
+        assertFalse(map.containsMapping("key1", "v4"));
+    }
+
+    @Test
+    void testGetValuesAsSetIsSafeCopy() {
+        final String[] values = { "v1", "v2", "v3" };
+        final MultiValuedMap<String, String> map = new 
HashSetValuedHashMap<>();
+        for (final String val : values) {
+            map.put("key1", val);
+        }
+
+        final Set<String> set = MultiMapUtils.getValuesAsSet(map, "key1");
+        set.add("v4");
+        assertFalse(map.containsMapping("key1", "v4"));
+    }
+
     @Test
     void testInvert() {
         final HashSetValuedHashMap<String, String> usages = new 
HashSetValuedHashMap<>();

Reply via email to