From d712ec3d493ea0c8b5dac72fba4c8c2427a7187a Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 16 Feb 2026 17:20:21 +0000 Subject: [PATCH] Minor optimization in Tomcat header adapters get method skips containsKey and instead checks if the enumeration has elements, which should give the same behavior other than for headers without values. See gh-36334 --- .../server/reactive/TomcatHeadersAdapter.java | 52 ++++++++++++------- .../server/reactive/HeadersAdaptersTests.java | 14 ++--- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java index cf72627fabb..38fd23dbb6f 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/TomcatHeadersAdapter.java @@ -65,12 +65,16 @@ class TomcatHeadersAdapter implements MultiValueMap { @Override public void addAll(String key, List values) { - values.forEach(value -> add(key, value)); + for (String value : values) { + add(key, value); + } } @Override public void addAll(MultiValueMap values) { - values.forEach(this::addAll); + for (Entry> entry : values.entrySet()) { + addAll(entry.getKey(), entry.getValue()); + } } @Override @@ -80,24 +84,28 @@ class TomcatHeadersAdapter implements MultiValueMap { @Override public void setAll(Map values) { - values.forEach(this::set); + for (Entry entry : values.entrySet()) { + set(entry.getKey(), entry.getValue()); + } } @Override public Map toSingleValueMap() { - Map singleValueMap = CollectionUtils.newLinkedHashMap(this.headers.size()); - this.keySet().forEach(key -> singleValueMap.put(key, getFirst(key))); - return singleValueMap; + Map map = CollectionUtils.newLinkedHashMap(this.headers.size()); + for (String name : this.keySet()) { + map.put(name, getFirst(name)); + } + return map; } @Override public int size() { Enumeration names = this.headers.names(); - Set deduplicated = new LinkedHashSet<>(); + Set set = new LinkedHashSet<>(this.headers.size()); while (names.hasMoreElements()) { - deduplicated.add(names.nextElement().toLowerCase(Locale.ROOT)); + set.add(names.nextElement().toLowerCase(Locale.ROOT)); } - return deduplicated.size(); + return set.size(); } @Override @@ -116,10 +124,10 @@ class TomcatHeadersAdapter implements MultiValueMap { @Override public boolean containsValue(Object value) { if (value instanceof String text) { - MessageBytes messageBytes = MessageBytes.newInstance(); - messageBytes.setString(text); + MessageBytes bytes = MessageBytes.newInstance(); + bytes.setString(text); for (int i = 0; i < this.headers.size(); i++) { - if (this.headers.getValue(i).equals(messageBytes)) { + if (this.headers.getValue(i).equals(bytes)) { return true; } } @@ -129,33 +137,38 @@ class TomcatHeadersAdapter implements MultiValueMap { @Override public @Nullable List get(Object key) { - if (containsKey(key)) { - return Collections.list(this.headers.values((String) key)); + if (key instanceof String headerName) { + Enumeration values = this.headers.values(headerName); + if (values.hasMoreElements()) { + return Collections.list(values); + } } return null; } @Override public @Nullable List put(String key, List value) { - List previousValues = get(key); + List previous = get(key); this.headers.removeHeader(key); value.forEach(v -> this.headers.addValue(key).setString(v)); - return previousValues; + return previous; } @Override public @Nullable List remove(Object key) { if (key instanceof String headerName) { - List previousValues = get(key); + List previous = get(key); this.headers.removeHeader(headerName); - return previousValues; + return previous; } return null; } @Override public void putAll(Map> map) { - map.forEach(this::put); + for (Entry> entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } } @Override @@ -258,6 +271,7 @@ class TomcatHeadersAdapter implements MultiValueMap { } } + private final class HeaderNamesIterator implements Iterator { private final Enumeration enumeration; diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/HeadersAdaptersTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/HeadersAdaptersTests.java index 4f50168d028..76ecb4d6a9c 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/HeadersAdaptersTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/HeadersAdaptersTests.java @@ -298,12 +298,14 @@ class HeadersAdaptersTests { static Stream nativeHeadersWithCasedEntries() { return Stream.of( - argumentSet("Netty", new Netty4HeadersAdapter(withHeaders(new DefaultHttpHeaders(), h -> h::add))), - argumentSet("Tomcat", new TomcatHeadersAdapter(withHeaders(new MimeHeaders(), - h -> (k, v) -> h.addValue(k).setString(v)))), - argumentSet("Jetty", new JettyHeadersAdapter(withHeaders(HttpFields.build(), h -> h::add))), - argumentSet("HttpComponents", new HttpComponentsHeadersAdapter(withHeaders(new HttpGet("https://example.com"), - h -> h::addHeader))) + argumentSet("Netty", new Netty4HeadersAdapter( + withHeaders(new DefaultHttpHeaders(), h -> h::add))), + argumentSet("Tomcat", new TomcatHeadersAdapter( + withHeaders(new MimeHeaders(), h -> (k, v) -> h.addValue(k).setString(v)))), + argumentSet("Jetty", new JettyHeadersAdapter( + withHeaders(HttpFields.build(), h -> h::add))), + argumentSet("HttpComponents", new HttpComponentsHeadersAdapter( + withHeaders(new HttpGet("https://example.com"), h -> h::addHeader))) ); }