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

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


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

commit 14620d02758e7218aa7bb82b38d9cd47ef6d1059
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    | 20 +----------------
 .../collections/TestCaseInsensitiveKeyMap.java     | 25 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  7 ++++++
 3 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java 
b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
index 45bf9f9886..bfca41d6c4 100644
--- a/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
+++ b/java/org/apache/tomcat/util/collections/CaseInsensitiveKeyMap.java
@@ -198,7 +198,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
@@ -208,24 +208,6 @@ public class CaseInsensitiveKeyMap<V> extends 
AbstractMap<String,V> {
     }
 
 
-    private record EntryImpl<V>(String key, V value) implements 
Entry<String,V> {
-
-        @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 0ca3985a31..20ba044caf 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -665,6 +665,13 @@
         challenges that specify a charset other than UTF-8, the only value
         RFC 7617 allows. (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