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

markt-asf pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/10.1.x by this push:
     new 3eb4913387 Fix Map.Entry contract for CaseInsensitiveKeyMap entries 
(#1075)
3eb4913387 is described below

commit 3eb4913387e936ca8b3c65aae682f0335bc1d8f0
Author: breken <[email protected]>
AuthorDate: Wed Nov 4 16:25:44 2026 +0800

    Fix Map.Entry contract for CaseInsensitiveKeyMap entries (#1075)
    
    The entries returned by entrySet() were a record, so equals() only
    matched other instances of that record and hashCode() did not follow the
    Map.Entry definition. As a result an entry was not equal to an
    equivalent entry from another map, and the map's hashCode() differed
    from that of an equal HashMap. Use AbstractMap.SimpleImmutableEntry,
    which implements the contract and still rejects setValue().
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    Co-authored-by: breken-ai <[email protected]>
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../util/collections/CaseInsensitiveKeyMap.java    | 28 +---------------------
 .../collections/TestCaseInsensitiveKeyMap.java     | 25 +++++++++++++++++++
 webapps/docs/changelog.xml                         |  7 ++++++
 3 files changed, 33 insertions(+), 27 deletions(-)

diff --git a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java 
b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
index e287dcd34c..8237a2f8e5 100644
--- a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
+++ b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
@@ -210,7 +210,7 @@ public class CaseInsensitiveKeyMap<V> extends 
AbstractMap<String,V> {
         @Override
         public Entry<String,V> next() {
             Entry<Key,V> entry = iterator.next();
-            return new EntryImpl<>(entry.getKey().getKey(), entry.getValue());
+            return new SimpleImmutableEntry<>(entry.getKey().getKey(), 
entry.getValue());
         }
 
         @Override
@@ -220,32 +220,6 @@ public class CaseInsensitiveKeyMap<V> extends 
AbstractMap<String,V> {
     }
 
 
-    private static class EntryImpl<V> implements Entry<String,V> {
-
-        private final String key;
-        private final V value;
-
-        EntryImpl(String key, V value) {
-            this.key = key;
-            this.value = value;
-        }
-
-        @Override
-        public String getKey() {
-            return key;
-        }
-
-        @Override
-        public V getValue() {
-            return value;
-        }
-
-        @Override
-        public V setValue(V value) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     private static class Key {
 
         private final String key;
diff --git 
a/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java 
b/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
index c61d29ca4d..fb3becc515 100644
--- a/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
+++ b/test/org/apache/tomcat/util/collections/TestCaseInsensitiveKeyMap.java
@@ -273,4 +273,29 @@ public class TestCaseInsensitiveKeyMap {
         iter.remove();
         Assert.assertTrue(map.isEmpty());
     }
+
+
+    @Test
+    public void testEntryEqualsAndHashCode() {
+        Object o1 = new Object();
+
+        CaseInsensitiveKeyMap<Object> map = new CaseInsensitiveKeyMap<>();
+        map.put("a", o1);
+
+        Map<String,Object> expected = new HashMap<>();
+        expected.put("a", o1);
+
+        Entry<String,Object> entry = map.entrySet().iterator().next();
+        Entry<String,Object> expectedEntry = 
expected.entrySet().iterator().next();
+
+        // Map.Entry contract
+        Assert.assertTrue(entry.equals(expectedEntry));
+        Assert.assertTrue(expectedEntry.equals(entry));
+        Assert.assertEquals(expectedEntry.hashCode(), entry.hashCode());
+
+        // Map contract: equal maps must have equal hash codes
+        Assert.assertEquals(expected, map);
+        Assert.assertEquals(map, expected);
+        Assert.assertEquals(expected.hashCode(), map.hashCode());
+    }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3ec2ee4d77..8d75fd432e 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -658,6 +658,13 @@
         use ISO-8859-1, the default used by Tomcat servers of this branch.
        (remm)
       </fix>
+      <fix>
+        Fix the entries returned by
+        <code>CaseInsensitiveKeyMap.entrySet()</code> so they implement the
+        <code>Map.Entry</code> <code>equals()</code> and 
<code>hashCode()</code>
+        contracts. This map backs the WebSocket handshake request and response
+        header maps. Pull request <pr>1075</pr> provided by breken-ai. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Web applications">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to