From 198e058e124f13aa9ba11287d941ff2c85121392 Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Wed, 19 Aug 2026 19:36:55 +0300 Subject: [PATCH 1/6] SOLR-18374: remove NamedList.NamedListEntry, scope MapWriterMap to its package Two deprecated members, two different remedies - the annotations themselves say so. NamedListEntry adds nothing to AbstractMap.SimpleEntry but a constructor, so it is replaced at all four production sites at once. They have to move together: three of them create the array (DebugComponent, HighlightComponent, TermVectorComponent) and the fourth, SolrPluginUtils.copyNamedListIntoArrayByDocPosInResponse, is the single filler that stores into all three. Widening the array's component type is safe by construction here, and that was measured rather than assumed: planting the mismatch on purpose - array of SimpleEntry while the filler still stored NamedListEntry - left DistributedDebugComponentTest at 5/5, because NamedListEntry IS-A SimpleEntry. A throwing control at the same place failed all 5, so the path is genuinely exercised and the green result was substantive. After the change the runtime component type and the stored type match exactly at all three creators; the declared type stays Map.Entry[], so removeNulls is untouched. MapWriterMap is NOT removed. Its own annotation reads "May keep but use package scope", and it has exactly one caller in the tree, NavigableObject.wrap, in the same package - so the class and its constructor drop public and keep working. The @Override methods stay public because they implement MapWriter. This is a source- and binary-incompatible change for out-of-tree code that constructed it directly, which is why the changelog says scoped rather than removed. Verified: compileJava (solrj, core, core tests), ecjLintMain, spotlessJavaCheck, renderJavadoc, and DistributedDebugComponentTest, CustomHighlightComponentTest, DistributedTermsComponentTest, TestDistributedSearch - 8 tests, 0 failures, counted from the JUnit XML rather than trusted from BUILD SUCCESSFUL. SOLR-18373 (#4761) also touches NamedList.java, in a different region - simulated the merge by applying this diff on top of a scratch merge of #4761 into origin/main; it applies cleanly. AI-assisted (Claude Sonnet 5) --- ...-remove-namedlistentry-and-scope-mapwritermap.yml | 8 ++++++++ .../solr/handler/component/DebugComponent.java | 3 ++- .../solr/handler/component/HighlightComponent.java | 3 ++- .../solr/handler/component/TermVectorComponent.java | 5 +++-- .../java/org/apache/solr/util/SolrPluginUtils.java | 3 ++- .../java/org/apache/solr/common/MapWriterMap.java | 6 +++--- .../java/org/apache/solr/common/util/NamedList.java | 12 ------------ 7 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml diff --git a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml new file mode 100644 index 000000000000..0ba366490e8b --- /dev/null +++ b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml @@ -0,0 +1,8 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Remove the deprecated NamedList.NamedListEntry helper class; use java.util.AbstractMap.SimpleEntry instead. The equally deprecated MapWriterMap is kept rather than removed, but is no longer public API - both the class and its constructor are now package-private, so obtain one through NavigableObject.wrap instead of constructing it directly. +type: removed +authors: + - name: Serhiy Bzhezytskyy +links: + - name: SOLR-18374 + url: https://issues.apache.org/jira/browse/SOLR-18374 diff --git a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java index 70dd1a401f22..ff599f52d7d4 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java @@ -22,6 +22,7 @@ import com.google.common.annotations.VisibleForTesting; import java.io.IOException; import java.lang.reflect.Array; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -216,7 +217,7 @@ public void finishStage(ResponseBuilder rb) { Map.Entry[] arr = (Map.Entry[]) - Array.newInstance(NamedList.NamedListEntry.class, rb.resultIds.size()); + Array.newInstance(AbstractMap.SimpleEntry.class, rb.resultIds.size()); // Will be set to true if there is at least one response with PURPOSE_GET_DEBUG boolean hasGetDebugResponses = false; diff --git a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java index 99f02dcf955e..a072a5640a26 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.lang.reflect.Array; +import java.util.AbstractMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -260,7 +261,7 @@ protected Object convertHighlights(NamedList hl) { protected Object[] newHighlightsArray(int size) { // Curious why this doesn't trigger an unchecked cast, but maybe the compiler is smart enough to // know - return (Object[]) Array.newInstance(NamedList.NamedListEntry.class, size); + return (Object[]) Array.newInstance(AbstractMap.SimpleEntry.class, size); } protected void addHighlights(Object[] objArr, Object obj, Map resultIds) { diff --git a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java index a4702e1d6137..7252adc17dde 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java @@ -20,6 +20,7 @@ import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -421,8 +422,8 @@ public void finishStage(ResponseBuilder rb) { @SuppressWarnings("unchecked") Map.Entry[] arr = - (NamedList.NamedListEntry[]) - Array.newInstance(NamedList.NamedListEntry.class, rb.resultIds.size()); + (Map.Entry[]) + Array.newInstance(AbstractMap.SimpleEntry.class, rb.resultIds.size()); for (ShardRequest sreq : rb.finished) { if ((sreq.purpose & ShardRequest.PURPOSE_GET_FIELDS) == 0 diff --git a/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java b/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java index ed6178be4f9b..43bf2ee3b113 100644 --- a/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java +++ b/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java @@ -29,6 +29,7 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -825,7 +826,7 @@ public static void copyNamedListIntoArrayByDocPosInResponse( ShardDoc sdoc = resultIds.get(id); if (sdoc != null) { // maybe null when rb.onePassDistributedQuery int idx = sdoc.positionInResponse; - destArr[idx] = new NamedList.NamedListEntry<>(id, val); + destArr[idx] = new AbstractMap.SimpleEntry<>(id, val); } }); } diff --git a/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java b/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java index 454898afc112..a2e084a5ba62 100644 --- a/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java +++ b/solr/solrj/src/java/org/apache/solr/common/MapWriterMap.java @@ -21,11 +21,11 @@ import java.util.List; import java.util.Map; -@Deprecated // see NavigableMap.wrap. May keep but use package scope. -public class MapWriterMap implements MapWriter { +/** Wraps a {@link Map} as a {@link MapWriter}; obtain via {@link NavigableObject#wrap(Object)}. */ +class MapWriterMap implements MapWriter { private final Map delegate; - public MapWriterMap(Map delegate) { + MapWriterMap(Map delegate) { this.delegate = delegate; } diff --git a/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java b/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java index e4f27c4025b6..f13a71f87237 100644 --- a/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java +++ b/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.io.Serializable; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -501,17 +500,6 @@ public SolrParams toSolrParams() { return new MultiMapSolrParams(map); } - /** - * Helper class implementing Map.Entry<String, T> to store the key-value relationship in - * NamedList (the keys of which are String-s) - */ - @Deprecated // use AbstractMap.SimpleEntry or Map.entry() (albeit no nulls) - public static final class NamedListEntry extends AbstractMap.SimpleEntry { - public NamedListEntry(String _key, T _value) { - super(_key, _value); - } - } - /** Iterates over the Map and sequentially adds its key/value pairs */ public boolean addAll(Map args) { for (Map.Entry entry : args.entrySet()) { From 29d513c39ce37f6bd0b95d4e0a9710f5ba5dd8b9 Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Thu, 20 Aug 2026 09:20:56 +0300 Subject: [PATCH 2/6] SOLR-18374: drop the changelog entry David Smiley: "these PRs you are working on, the changelog isn't necessary. Removing deprecated things generally don't need changelogs unless the thing in question is believed to be highly visible/used." Note: this will fail the "Check changelog entry" CI gate, since our changed files are src/java, not docs/tests-only, and only a maintainer can apply the no-changelog label to skip it -- flagging on the PR. AI-assisted (Claude Sonnet 5) --- ...18374-remove-namedlistentry-and-scope-mapwritermap.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml diff --git a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml deleted file mode 100644 index 0ba366490e8b..000000000000 --- a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml +++ /dev/null @@ -1,8 +0,0 @@ -# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc -title: Remove the deprecated NamedList.NamedListEntry helper class; use java.util.AbstractMap.SimpleEntry instead. The equally deprecated MapWriterMap is kept rather than removed, but is no longer public API - both the class and its constructor are now package-private, so obtain one through NavigableObject.wrap instead of constructing it directly. -type: removed -authors: - - name: Serhiy Bzhezytskyy -links: - - name: SOLR-18374 - url: https://issues.apache.org/jira/browse/SOLR-18374 From 83db90f859303356325c8b57ff4426bf7dd89606 Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Thu, 20 Aug 2026 11:59:43 +0300 Subject: [PATCH 3/6] Revert "SOLR-18374: drop the changelog entry" This reverts commit 29d513c39ce37f6bd0b95d4e0a9710f5ba5dd8b9. --- ...18374-remove-namedlistentry-and-scope-mapwritermap.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml diff --git a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml new file mode 100644 index 000000000000..0ba366490e8b --- /dev/null +++ b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml @@ -0,0 +1,8 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Remove the deprecated NamedList.NamedListEntry helper class; use java.util.AbstractMap.SimpleEntry instead. The equally deprecated MapWriterMap is kept rather than removed, but is no longer public API - both the class and its constructor are now package-private, so obtain one through NavigableObject.wrap instead of constructing it directly. +type: removed +authors: + - name: Serhiy Bzhezytskyy +links: + - name: SOLR-18374 + url: https://issues.apache.org/jira/browse/SOLR-18374 From 8aec032a41ce43f35d07161b8f0eb484abf911a1 Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Thu, 20 Aug 2026 14:19:54 +0300 Subject: [PATCH 4/6] SOLR-18374: document when a changelog entry may be skipped janhoy noted the actual criteria for skipping a changelog entry lives only in gradle/changelog.gradle's comments, visible only after already deciding to scaffold one. Adds a short section to dev-docs/changelog.adoc, distilled from David Smiley's and janhoy's own criteria stated on this PR. --- dev-docs/changelog.adoc | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/dev-docs/changelog.adoc b/dev-docs/changelog.adoc index 0a0e9e5a1bd7..eaf36f860da2 100644 --- a/dev-docs/changelog.adoc +++ b/dev-docs/changelog.adoc @@ -120,6 +120,19 @@ The changelog has comments to help you fill it out. Remove them after filling o TIP: Aliases for the `writeChangelog` task are `changelog` and `newChangelog`. +=== 3.2 When a changelog entry may be skipped + +A changelog entry is not needed for: + +* Changes confined to *test code only* (nothing user-visible changed). +* Changes to a *non-public API* (package-private or internal-only members). +* Removing a single, effectively unused public constant, or another change this minor. + +For anything else -- including removing a deprecated *public* member -- add one, even if narrow: for +external contributions especially, the entry is also how the contribution gets attribution. If a PR makes +several small, related removals (e.g. multiple deprecated members in the same module), consider grouping +them into one YAML fragment with multiple `links` entries rather than one file per change. + == 4. Changelog Validation in Pull Requests The `validate-changelog` GitHub workflow automatically checks that: @@ -127,7 +140,8 @@ The `validate-changelog` GitHub workflow automatically checks that: . **CHANGES.txt is not edited directly** - All changes must use the YAML fragment approach . **A changelog entry is added** - Code changes must include a corresponding YAML file in `changelog/unreleased/` -If your change does not require a changelog entry, it is still possible to merge the PR. +If your change does not require a changelog entry (see "3.2" above), it is still possible to merge the PR: a +committer can add the `no-changelog` label to skip the check. == 5. For release managers From a73f9a79eb18bcf9dd23a0493a853f6075f02eda Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Thu, 20 Aug 2026 14:25:46 +0300 Subject: [PATCH 5/6] Revert "SOLR-18374: document when a changelog entry may be skipped" This reverts commit 8aec032a41ce43f35d07161b8f0eb484abf911a1. --- dev-docs/changelog.adoc | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/dev-docs/changelog.adoc b/dev-docs/changelog.adoc index eaf36f860da2..0a0e9e5a1bd7 100644 --- a/dev-docs/changelog.adoc +++ b/dev-docs/changelog.adoc @@ -120,19 +120,6 @@ The changelog has comments to help you fill it out. Remove them after filling o TIP: Aliases for the `writeChangelog` task are `changelog` and `newChangelog`. -=== 3.2 When a changelog entry may be skipped - -A changelog entry is not needed for: - -* Changes confined to *test code only* (nothing user-visible changed). -* Changes to a *non-public API* (package-private or internal-only members). -* Removing a single, effectively unused public constant, or another change this minor. - -For anything else -- including removing a deprecated *public* member -- add one, even if narrow: for -external contributions especially, the entry is also how the contribution gets attribution. If a PR makes -several small, related removals (e.g. multiple deprecated members in the same module), consider grouping -them into one YAML fragment with multiple `links` entries rather than one file per change. - == 4. Changelog Validation in Pull Requests The `validate-changelog` GitHub workflow automatically checks that: @@ -140,8 +127,7 @@ The `validate-changelog` GitHub workflow automatically checks that: . **CHANGES.txt is not edited directly** - All changes must use the YAML fragment approach . **A changelog entry is added** - Code changes must include a corresponding YAML file in `changelog/unreleased/` -If your change does not require a changelog entry (see "3.2" above), it is still possible to merge the PR: a -committer can add the `no-changelog` label to skip the check. +If your change does not require a changelog entry, it is still possible to merge the PR. == 5. For release managers From 09894e0997cbd0b4807e12338f596d250bf3218b Mon Sep 17 00:00:00 2001 From: Serhiy Bzhezytskyy Date: Thu, 20 Aug 2026 15:50:28 +0300 Subject: [PATCH 6/6] SOLR-18374: drop the changelog entry again --- ...18374-remove-namedlistentry-and-scope-mapwritermap.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml diff --git a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml b/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml deleted file mode 100644 index 0ba366490e8b..000000000000 --- a/changelog/unreleased/SOLR-18374-remove-namedlistentry-and-scope-mapwritermap.yml +++ /dev/null @@ -1,8 +0,0 @@ -# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc -title: Remove the deprecated NamedList.NamedListEntry helper class; use java.util.AbstractMap.SimpleEntry instead. The equally deprecated MapWriterMap is kept rather than removed, but is no longer public API - both the class and its constructor are now package-private, so obtain one through NavigableObject.wrap instead of constructing it directly. -type: removed -authors: - - name: Serhiy Bzhezytskyy -links: - - name: SOLR-18374 - url: https://issues.apache.org/jira/browse/SOLR-18374