From a871f609ea2621934ed4b13e06e912a3cb98c124 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 21 Apr 2019 15:17:40 +0200 Subject: [PATCH 1/6] Introduce failing tests for HttpHeaders See gh-22821 --- .../http/HttpHeadersTests.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java index bb32e873bc7..33ec3e29c9a 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -36,6 +36,7 @@ import java.util.Map.Entry; import java.util.TimeZone; import org.hamcrest.Matchers; +import org.junit.Ignore; import org.junit.Test; import static org.hamcrest.Matchers.*; @@ -559,6 +560,36 @@ public class HttpHeadersTests { assertEquals("Bearer foo", authorization); } + @Test + @Ignore("Disabled until gh-22821 is resolved") + public void removalFromKeySetRemovesEntryFromUnderlyingMap() { + String headerName = "MyHeader"; + String headerValue = "value"; + + assertTrue(headers.isEmpty()); + headers.add(headerName, headerValue); + assertTrue(headers.containsKey(headerName)); + headers.keySet().removeIf(key -> key.equals(headerName)); + assertTrue(headers.isEmpty()); + headers.add(headerName, headerValue); + assertEquals(headerValue, headers.get(headerName)); + } + + @Test + @Ignore("Disabled until gh-22821 is resolved") + public void removalFromEntrySetRemovesEntryFromUnderlyingMap() { + String headerName = "MyHeader"; + String headerValue = "value"; + + assertTrue(headers.isEmpty()); + headers.add(headerName, headerValue); + assertTrue(headers.containsKey(headerName)); + headers.entrySet().removeIf(entry -> entry.getKey().equals(headerName)); + assertTrue(headers.isEmpty()); + headers.add(headerName, headerValue); + assertEquals(headerValue, headers.get(headerName)); + } + @Test public void readOnlyHttpHeadersRetainEntrySetOrder() { headers.add("aardvark", "enigma"); From aa69703f3b0f92b1c7eaaf62b34ef8c7b251fc5c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Thu, 25 Apr 2019 15:36:18 -0700 Subject: [PATCH 2/6] Fix LinkedCaseInsensitiveMap collection methods Ensure that results returned from keySet, entrySet & values are tracked to remove case insensitive keys from the source map. Closes gh-22821 --- .../util/LinkedCaseInsensitiveMap.java | 251 +++++++++++++++++- .../util/LinkedCaseInsensitiveMapTests.java | 92 ++++++- .../http/HttpHeadersTests.java | 7 +- 3 files changed, 338 insertions(+), 12 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java index ed55e678053..bf12dabf921 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,17 @@ package org.springframework.util; import java.io.Serializable; +import java.util.AbstractCollection; +import java.util.AbstractSet; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; import java.util.function.Function; import org.springframework.lang.Nullable; @@ -37,6 +42,7 @@ import org.springframework.lang.Nullable; *

Does not support {@code null} keys. * * @author Juergen Hoeller + * @author Phillip Webb * @since 3.0 * @param the value type */ @@ -49,6 +55,12 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Locale locale; + private transient Set keySet; + + private transient Collection values; + + private transient Set> entrySet; + /** * Create a new LinkedCaseInsensitiveMap that stores case-insensitive keys @@ -98,7 +110,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable protected boolean removeEldestEntry(Map.Entry eldest) { boolean doRemove = LinkedCaseInsensitiveMap.this.removeEldestEntry(eldest); if (doRemove) { - caseInsensitiveKeys.remove(convertKey(eldest.getKey())); + removeCaseInsensitiveKey(eldest.getKey()); } return doRemove; } @@ -208,7 +220,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable @Nullable public V remove(Object key) { if (key instanceof String) { - String caseInsensitiveKey = this.caseInsensitiveKeys.remove(convertKey((String) key)); + String caseInsensitiveKey = removeCaseInsensitiveKey((String) key); if (caseInsensitiveKey != null) { return this.targetMap.remove(caseInsensitiveKey); } @@ -224,17 +236,32 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable @Override public Set keySet() { - return this.targetMap.keySet(); + Set keySet = this.keySet; + if (keySet == null) { + keySet = new KeySet(this.targetMap.keySet()); + this.keySet = keySet; + } + return keySet; } @Override public Collection values() { - return this.targetMap.values(); + Collection values = this.values; + if (values == null) { + values = new Values(this.targetMap.values()); + this.values = values; + } + return values; } @Override public Set> entrySet() { - return this.targetMap.entrySet(); + Set> entrySet = this.entrySet; + if (entrySet == null) { + entrySet = new EntrySet(this.targetMap.entrySet()); + this.entrySet = entrySet; + } + return entrySet; } @Override @@ -293,4 +320,216 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable return false; } + private String removeCaseInsensitiveKey(String key) { + return this.caseInsensitiveKeys.remove(convertKey(key)); + } + + + private class KeySet extends AbstractSet { + + private final Set delegate; + + + KeySet(Set delegate) { + this.delegate = delegate; + } + + + @Override + public int size() { + return this.delegate.size(); + } + + @Override + public boolean contains(Object o) { + return this.delegate.contains(o); + } + + @Override + public Iterator iterator() { + return new KeySetIterator(); + } + + @Override + public boolean remove(Object o) { + return LinkedCaseInsensitiveMap.this.remove(o) != null; + } + + @Override + public void clear() { + LinkedCaseInsensitiveMap.this.clear(); + } + + @Override + public Spliterator spliterator() { + return this.delegate.spliterator(); + } + + @Override + public void forEach(Consumer action) { + this.delegate.forEach(action); + } + + } + + + private class Values extends AbstractCollection { + + private final Collection delegate; + + + Values(Collection delegate) { + this.delegate = delegate; + } + + + @Override + public int size() { + return this.delegate.size(); + } + + @Override + public boolean contains(Object o) { + return this.delegate.contains(o); + } + + @Override + public Iterator iterator() { + return new ValuesIterator(); + } + + @Override + public void clear() { + LinkedCaseInsensitiveMap.this.clear(); + } + + @Override + public Spliterator spliterator() { + return this.delegate.spliterator(); + } + + @Override + public void forEach(Consumer action) { + this.delegate.forEach(action); + } + + } + + + private class EntrySet extends AbstractSet> { + + private final Set> delegate; + + + public EntrySet(Set> delegate) { + this.delegate = delegate; + } + + + @Override + public int size() { + return this.delegate.size(); + } + + @Override + public boolean contains(Object o) { + return this.delegate.contains(o); + } + + @Override + public Iterator> iterator() { + return new EntrySetIterator(); + } + + + @Override + @SuppressWarnings("unchecked") + public boolean remove(Object o) { + if (this.delegate.remove(o)) { + removeCaseInsensitiveKey(((Map.Entry) o).getKey()); + return true; + } + return false; + } + + + @Override + public void clear() { + this.delegate.clear(); + caseInsensitiveKeys.clear(); + } + + @Override + public Spliterator> spliterator() { + return this.delegate.spliterator(); + } + + @Override + public void forEach(Consumer> action) { + this.delegate.forEach(action); + } + + } + + + private class EntryIterator { + + private final Iterator> delegate; + + private Entry last; + + public EntryIterator() { + this.delegate = targetMap.entrySet().iterator(); + } + + public Entry nextEntry() { + Entry entry = this.delegate.next(); + this.last = entry; + return entry; + } + + public boolean hasNext() { + return this.delegate.hasNext(); + } + + public void remove() { + this.delegate.remove(); + if(this.last != null) { + removeCaseInsensitiveKey(this.last.getKey()); + this.last = null; + } + } + + } + + + private class KeySetIterator extends EntryIterator implements Iterator { + + @Override + public String next() { + return nextEntry().getKey(); + } + + } + + + private class ValuesIterator extends EntryIterator implements Iterator { + + @Override + public V next() { + return nextEntry().getValue(); + } + + } + + + private class EntrySetIterator extends EntryIterator implements Iterator> { + + @Override + public Entry next() { + return nextEntry(); + } + + } + } diff --git a/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java index f698f764c6f..c93324bea93 100644 --- a/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java +++ b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,17 @@ package org.springframework.util; +import java.util.Iterator; + import org.junit.Test; import static org.junit.Assert.*; /** + * Tests for {@link LinkedCaseInsensitiveMap}. + * * @author Juergen Hoeller + * @author Phillip Webb */ public class LinkedCaseInsensitiveMapTests { @@ -127,4 +132,89 @@ public class LinkedCaseInsensitiveMapTests { assertEquals("value2", copy.get("Key")); } + + @Test + public void clearFromKeySet() { + map.put("key", "value"); + map.keySet().clear(); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromKeySet() { + map.put("key", "value"); + map.keySet().remove("key"); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromKeySetViaIterator() { + map.put("key", "value"); + nextAndRemove(map.keySet().iterator()); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void clearFromValues() { + map.put("key", "value"); + map.values().clear(); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromValues() { + map.put("key", "value"); + map.values().remove("value"); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromValuesViaIterator() { + map.put("key", "value"); + nextAndRemove(map.values().iterator()); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void clearFromEntrySet() { + map.put("key", "value"); + map.entrySet().clear(); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromEntrySet() { + map.put("key", "value"); + map.entrySet().remove(map.entrySet().iterator().next()); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + @Test + public void removeFromEntrySetViaIterator() { + map.put("key", "value"); + nextAndRemove(map.entrySet().iterator()); + assertEquals(0, map.size()); + map.computeIfAbsent("key", k -> "newvalue"); + assertEquals("newvalue", map.get("key")); + } + + private void nextAndRemove(Iterator iterator) { + iterator.next(); + iterator.remove(); + } + } diff --git a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java index 33ec3e29c9a..fde2ee17f78 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -36,7 +36,6 @@ import java.util.Map.Entry; import java.util.TimeZone; import org.hamcrest.Matchers; -import org.junit.Ignore; import org.junit.Test; import static org.hamcrest.Matchers.*; @@ -561,7 +560,6 @@ public class HttpHeadersTests { } @Test - @Ignore("Disabled until gh-22821 is resolved") public void removalFromKeySetRemovesEntryFromUnderlyingMap() { String headerName = "MyHeader"; String headerValue = "value"; @@ -572,11 +570,10 @@ public class HttpHeadersTests { headers.keySet().removeIf(key -> key.equals(headerName)); assertTrue(headers.isEmpty()); headers.add(headerName, headerValue); - assertEquals(headerValue, headers.get(headerName)); + assertEquals(headerValue, headers.get(headerName).get(0)); } @Test - @Ignore("Disabled until gh-22821 is resolved") public void removalFromEntrySetRemovesEntryFromUnderlyingMap() { String headerName = "MyHeader"; String headerValue = "value"; @@ -587,7 +584,7 @@ public class HttpHeadersTests { headers.entrySet().removeIf(entry -> entry.getKey().equals(headerName)); assertTrue(headers.isEmpty()); headers.add(headerName, headerValue); - assertEquals(headerValue, headers.get(headerName)); + assertEquals(headerValue, headers.get(headerName).get(0)); } @Test From bd28bb1f56176ce2ecfe22ddcf0a00906bcaf8db Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 16 Sep 2019 12:33:20 +0200 Subject: [PATCH 3/6] Add additional tests for HttpHeaders.keySet() operations See gh-22821 --- .../http/HttpHeadersTests.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java index fde2ee17f78..8e65470a611 100644 --- a/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java +++ b/spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java @@ -38,6 +38,7 @@ import java.util.TimeZone; import org.hamcrest.Matchers; import org.junit.Test; +import static java.util.stream.Collectors.toList; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -559,6 +560,80 @@ public class HttpHeadersTests { assertEquals("Bearer foo", authorization); } + @Test // https://github.com/spring-projects/spring-framework/issues/23633 + public void keySetRemove() { + // Given + headers.add("Alpha", "apple"); + headers.add("Bravo", "banana"); + assertEquals(2, headers.size()); + assertTrue("Alpha should be present", headers.containsKey("Alpha")); + assertTrue("Bravo should be present", headers.containsKey("Bravo")); + assertArrayEquals(new String[] {"Alpha", "Bravo"}, headers.keySet().toArray()); + + // When + boolean removed = headers.keySet().remove("Alpha"); + + // Then + assertTrue(removed); + assertFalse(headers.keySet().remove("Alpha")); + assertEquals(1, headers.size()); + assertFalse("Alpha should have been removed", headers.containsKey("Alpha")); + assertTrue("Bravo should be present", headers.containsKey("Bravo")); + assertArrayEquals(new String[] {"Bravo"}, headers.keySet().toArray()); + assertEquals(Collections.singletonMap("Bravo", Arrays.asList("banana")).entrySet(), headers.entrySet()); + } + + @Test + public void keySetOperations() { + headers.add("Alpha", "apple"); + headers.add("Bravo", "banana"); + assertEquals(2, headers.size()); + + // size() + assertEquals(2, headers.keySet().size()); + + // contains() + assertTrue("Alpha should be present", headers.keySet().contains("Alpha")); + assertTrue("alpha should be present", headers.keySet().contains("alpha")); + assertTrue("Bravo should be present", headers.keySet().contains("Bravo")); + assertTrue("BRAVO should be present", headers.keySet().contains("BRAVO")); + assertFalse("Charlie should not be present", headers.keySet().contains("Charlie")); + + // toArray() + assertArrayEquals(new String[] {"Alpha", "Bravo"}, headers.keySet().toArray()); + + // spliterator() via stream() + assertEquals(Arrays.asList("Alpha", "Bravo"), headers.keySet().stream().collect(toList())); + + // iterator() + List results = new ArrayList<>(); + headers.keySet().iterator().forEachRemaining(results::add); + assertEquals(Arrays.asList("Alpha", "Bravo"), results); + + // remove() + assertTrue(headers.keySet().remove("Alpha")); + assertEquals(1, headers.size()); + assertFalse(headers.keySet().remove("Alpha")); + + // clear() + headers.keySet().clear(); + assertEquals(0, headers.size()); + + // Unsupported operations + unsupported(() -> headers.keySet().add("x")); + unsupported(() -> headers.keySet().addAll(Collections.singleton("enigma"))); + } + + private static void unsupported(Runnable runnable) { + try { + runnable.run(); + fail("should have thrown an UnsupportedOperationException"); + } + catch (UnsupportedOperationException e) { + // expected + } + } + @Test public void removalFromKeySetRemovesEntryFromUnderlyingMap() { String headerName = "MyHeader"; From 60976e4116fc48f08a3e6d5e0700d8c30b0339b9 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 26 Apr 2019 23:10:18 +0200 Subject: [PATCH 4/6] Add missing nullable declarations See gh-22821 --- .../util/LinkedCaseInsensitiveMap.java | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java index bf12dabf921..cb319718df6 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -55,10 +55,13 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Locale locale; + @Nullable private transient Set keySet; + @Nullable private transient Collection values; + @Nullable private transient Set> entrySet; @@ -320,6 +323,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable return false; } + @Nullable private String removeCaseInsensitiveKey(String key) { return this.caseInsensitiveKeys.remove(convertKey(key)); } @@ -329,12 +333,10 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Set delegate; - KeySet(Set delegate) { this.delegate = delegate; } - @Override public int size() { return this.delegate.size(); @@ -369,7 +371,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public void forEach(Consumer action) { this.delegate.forEach(action); } - } @@ -377,12 +378,10 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Collection delegate; - Values(Collection delegate) { this.delegate = delegate; } - @Override public int size() { return this.delegate.size(); @@ -412,7 +411,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public void forEach(Consumer action) { this.delegate.forEach(action); } - } @@ -420,12 +418,10 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Set> delegate; - public EntrySet(Set> delegate) { this.delegate = delegate; } - @Override public int size() { return this.delegate.size(); @@ -441,7 +437,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable return new EntrySetIterator(); } - @Override @SuppressWarnings("unchecked") public boolean remove(Object o) { @@ -452,7 +447,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable return false; } - @Override public void clear() { this.delegate.clear(); @@ -468,7 +462,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public void forEach(Consumer> action) { this.delegate.forEach(action); } - } @@ -476,6 +469,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Iterator> delegate; + @Nullable private Entry last; public EntryIterator() { @@ -494,12 +488,11 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public void remove() { this.delegate.remove(); - if(this.last != null) { + if (this.last != null) { removeCaseInsensitiveKey(this.last.getKey()); this.last = null; } } - } @@ -509,7 +502,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public String next() { return nextEntry().getKey(); } - } @@ -519,7 +511,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public V next() { return nextEntry().getValue(); } - } @@ -529,7 +520,6 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable public Entry next() { return nextEntry(); } - } } From c8f20815ef2211297fc9d83a2b02ab0958d7ae47 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 8 May 2019 17:52:28 +0200 Subject: [PATCH 5/6] Revise LinkedCaseInsensitiveMap's lazy key/value/entry collections Closes gh-22926 --- .../util/LinkedCaseInsensitiveMap.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java index cb319718df6..5cdd9f12438 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -56,13 +56,13 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable private final Locale locale; @Nullable - private transient Set keySet; + private transient volatile Set keySet; @Nullable - private transient Collection values; + private transient volatile Collection values; @Nullable - private transient Set> entrySet; + private transient volatile Set> entrySet; /** @@ -465,7 +465,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable } - private class EntryIterator { + private abstract class EntryIterator implements Iterator { private final Iterator> delegate; @@ -476,16 +476,18 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable this.delegate = targetMap.entrySet().iterator(); } - public Entry nextEntry() { + protected Entry nextEntry() { Entry entry = this.delegate.next(); this.last = entry; return entry; } + @Override public boolean hasNext() { return this.delegate.hasNext(); } + @Override public void remove() { this.delegate.remove(); if (this.last != null) { @@ -496,7 +498,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable } - private class KeySetIterator extends EntryIterator implements Iterator { + private class KeySetIterator extends EntryIterator { @Override public String next() { @@ -505,7 +507,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable } - private class ValuesIterator extends EntryIterator implements Iterator { + private class ValuesIterator extends EntryIterator { @Override public V next() { @@ -514,7 +516,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable } - private class EntrySetIterator extends EntryIterator implements Iterator> { + private class EntrySetIterator extends EntryIterator> { @Override public Entry next() { From d09f53769945d2c1a5833cf942dcf81c6febf379 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 16 Sep 2019 12:43:13 +0200 Subject: [PATCH 6/6] Annotate Object#equals parameter with @nullable See gh-23093 Co-authored-by: Sebastien Deleuze --- .../java/org/springframework/util/LinkedCaseInsensitiveMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java index 5cdd9f12438..1b70fa55509 100644 --- a/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java +++ b/spring-core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -273,7 +273,7 @@ public class LinkedCaseInsensitiveMap implements Map, Serializable } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { return this.targetMap.equals(obj); }