http-client-branch: review comment - HttpHeaders::hashCode implementation doesn't obey its specification http-client-branch
authordfuchs
Wed, 20 Jun 2018 11:52:31 +0100
branchhttp-client-branch
changeset 56785 62937a37a291
parent 56783 7add69e2fb68
child 56786 e550e715c4d3
http-client-branch: review comment - HttpHeaders::hashCode implementation doesn't obey its specification
src/java.net.http/share/classes/java/net/http/HttpHeaders.java
test/jdk/java/net/httpclient/HttpHeadersOf.java
--- a/src/java.net.http/share/classes/java/net/http/HttpHeaders.java	Tue Jun 19 16:33:07 2018 +0100
+++ b/src/java.net.http/share/classes/java/net/http/HttpHeaders.java	Wed Jun 20 11:52:31 2018 +0100
@@ -153,7 +153,11 @@
      * @return the hash-code value for this HTTP headers
      */
     public final int hashCode() {
-        return map().hashCode();
+        int h = 0;
+        for (Map.Entry<String, List<String>> e : map().entrySet()) {
+            h += entryHash(e);
+        }
+        return h;
     }
 
     /**
@@ -218,6 +222,15 @@
         this.headers = headers;
     }
 
+    private static final int entryHash(Map.Entry<String, List<String>> e) {
+        String key = e.getKey();
+        List<String> value = e.getValue();
+        // we know that by construction key and values can't be null
+        int keyHash = key.toLowerCase(Locale.ROOT).hashCode();
+        int valueHash = value.hashCode();
+        return keyHash ^ valueHash;
+    }
+
     // Returns a new HTTP headers after performing a structural copy and filtering.
     private static HttpHeaders headersOf(Map<String,List<String>> map,
                                          BiPredicate<String,String> filter) {
--- a/test/jdk/java/net/httpclient/HttpHeadersOf.java	Tue Jun 19 16:33:07 2018 +0100
+++ b/test/jdk/java/net/httpclient/HttpHeadersOf.java	Wed Jun 20 11:52:31 2018 +0100
@@ -195,6 +195,32 @@
         }
     }
 
+    @Test
+    public void testEqualsAndHashCode() {
+        List<Map<String, List<String>>> maps = List.of(
+                Map.of("Accept-Encoding", List.of("gzip, deflate")),
+                Map.of("accept-encoding", List.of("gzip, deflate")),
+                Map.of("AccePT-ENCoding", List.of("gzip, deflate")),
+                Map.of("ACCept-EncodING", List.of("gzip, deflate")),
+                Map.of("ACCEPT-ENCODING", List.of("gzip, deflate"))
+        );
+        int mapDiffer = 0;
+        int mapHashDiffer = 0;
+        for (Map<String, List<String>> m1 : maps) {
+            HttpHeaders h1 = HttpHeaders.of(m1, ACCEPT_ALL);
+            for (Map<String, List<String>> m2 : maps) {
+                HttpHeaders h2 = HttpHeaders.of(m2, ACCEPT_ALL);
+                if (!m1.equals(m2)) mapDiffer++;
+                if (m1.hashCode() != m2.hashCode()) mapHashDiffer++;
+                assertEquals(h1, h2, "HttpHeaders differ");
+                assertEquals(h1.hashCode(), h2.hashCode(),
+                        "hashCode differ for " + List.of(m1,m2));
+            }
+        }
+        assertTrue(mapDiffer > 0, "all maps were equal!");
+        assertTrue(mapHashDiffer > 0, "all maps had same hashCode!");
+    }
+
     @DataProvider(name = "valueAsLong")
     public Object[][] valueAsLong() {
         return new Object[][] {