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 95283b08e Do not mutate the input map in
SwitchTransformer.switchTransformer (#696)
95283b08e is described below
commit 95283b08ea1ec83b09b4bb8ae0c8004da5476b8d
Author: Vasiliy Mikhailov <[email protected]>
AuthorDate: Sun Jun 28 16:19:47 2026 +0400
Do not mutate the input map in SwitchTransformer.switchTransformer (#696)
* Do not mutate the input map in SwitchTransformer.switchTransformer
switchTransformer(Map) extracted the default with map.remove(null), which
removes the null key from the caller list map as a side effect. Use
map.get(null) so the factory method leaves the input map unchanged.
* Declutter new test.
* Fix mess in test.
---------
Co-authored-by: Gary Gregory <[email protected]>
---
.../collections4/functors/SwitchTransformer.java | 12 ++---
.../functors/SwitchTransformerMapMutatesTest.java | 52 ++++++++++++++++++++++
2 files changed, 59 insertions(+), 5 deletions(-)
diff --git
a/src/main/java/org/apache/commons/collections4/functors/SwitchTransformer.java
b/src/main/java/org/apache/commons/collections4/functors/SwitchTransformer.java
index 213d1d5b9..a1dd1b623 100644
---
a/src/main/java/org/apache/commons/collections4/functors/SwitchTransformer.java
+++
b/src/main/java/org/apache/commons/collections4/functors/SwitchTransformer.java
@@ -17,6 +17,7 @@
package org.apache.commons.collections4.functors;
import java.io.Serializable;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -63,9 +64,10 @@ public class SwitchTransformer<T, R> implements
Transformer<T, R>, Serializable
if (map.isEmpty()) {
return ConstantTransformer.<I, O>nullTransformer();
}
- // convert to array like this to guarantee iterator() ordering
- final Transformer<? super I, ? extends O> defaultTransformer =
map.remove(null);
- final int size = map.size();
+ // copy so the caller's map is not mutated; LinkedHashMap preserves
iterator() ordering
+ final Map<Predicate<? super I>, Transformer<? super I, ? extends O>>
entries = new LinkedHashMap<>(map);
+ final Transformer<? super I, ? extends O> defaultTransformer =
entries.remove(null);
+ final int size = entries.size();
if (size == 0) {
return (Transformer<I, O>) (defaultTransformer == null ?
ConstantTransformer.<I, O>nullTransformer() :
defaultTransformer);
@@ -73,8 +75,8 @@ public class SwitchTransformer<T, R> implements
Transformer<T, R>, Serializable
final Transformer<? super I, ? extends O>[] transformers = new
Transformer[size];
final Predicate<? super I>[] preds = new Predicate[size];
int i = 0;
- for (final Map.Entry<? extends Predicate<? super I>,
- ? extends Transformer<? super I, ? extends O>>
entry : map.entrySet()) {
+ for (final Map.Entry<Predicate<? super I>,
+ Transformer<? super I, ? extends O>> entry :
entries.entrySet()) {
preds[i] = entry.getKey();
transformers[i] = entry.getValue();
i++;
diff --git
a/src/test/java/org/apache/commons/collections4/functors/SwitchTransformerMapMutatesTest.java
b/src/test/java/org/apache/commons/collections4/functors/SwitchTransformerMapMutatesTest.java
new file mode 100644
index 000000000..3cde12068
--- /dev/null
+++
b/src/test/java/org/apache/commons/collections4/functors/SwitchTransformerMapMutatesTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.collections4.functors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.Transformer;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests that SwitchTransformer.switchTransformer(Map) does not mutate the
input map.
+ */
+class SwitchTransformerMapMutatesTest {
+
+ /**
+ * Tests that switchTransformer(Map) does NOT mutate the input map by
removing the null key.
+ */
+ @Test
+ void testSwitchTransformerMapDoesNotMutateInput() {
+ final Transformer<String, String> defaultTransformer =
ConstantTransformer.constantTransformer("default");
+ final Transformer<String, String> transformer =
ConstantTransformer.constantTransformer("value");
+ final Predicate<String> predicate = NullPredicate.nullPredicate();
+ final Map<Predicate<String>, Transformer<String, String>> map = new
LinkedHashMap<>();
+ map.put(null, defaultTransformer);
+ map.put(predicate, transformer);
+ final int sizeBefore = map.size();
+ assertEquals(2, sizeBefore);
+ // Call the factory method
+ SwitchTransformer.switchTransformer(map);
+ // The map should NOT have been mutated - null key must still be
present
+ final int sizeAfter = map.size();
+ assertEquals(sizeBefore, sizeAfter, "switchTransformer must not mutate
the input map; expected size");
+ }
+}