From 1fdae895894faed9d7e87b1eb8e2e8d2d6b6d80e Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Sat, 17 Oct 2026 04:08:55 +0530 Subject: [PATCH 1/5] minor bug fix --- .../apache/solr/handler/SolrConfigHandler.java | 4 +++- .../apache/solr/handler/admin/api/GetConfig.java | 15 ++++++++++++++- .../solr/handler/admin/api/GetConfigTest.java | 5 ++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java index 08614a0a4bc6..6c8c0db4250f 100644 --- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java @@ -194,8 +194,10 @@ private String getDefaultPath() { private void handleGET() { if (parts.size() == 1) { // this is the whole config. sent out the whole payload + // v1 keeps internal section names (e.g. searchComponent); plurals are v2 only V2ApiUtils.squashIntoSolrResponseWithoutHeader( - resp, new GetConfig(req).getConfig(req.getParams().getBool("expandParams", false))); + resp, + new GetConfig(req).getConfig(req.getParams().getBool("expandParams", false),false)); } else { if (ConfigOverlay.NAME.equals(parts.get(1))) { V2ApiUtils.squashIntoSolrResponseWithoutHeader(resp, new GetConfig(req).getOverlay()); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java index 1bc7db362bd9..0b3e861f3a72 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java @@ -98,9 +98,22 @@ public GetConfig(SolrQueryRequest solrQueryRequest) { @Override @PermissionName(CONFIG_READ_PERM) public ConfigInfoResponse getConfig(boolean expandParams) { + return getConfig(expandParams, true); + } + + public ConfigInfoResponse getConfig(boolean expandParams, boolean useExternalComponentNames) { final var response = instantiateJerseyResponse(ConfigInfoResponse.class); - response.config = buildConfigMap(solrQueryRequest, expandParams); + Map configMap = buildConfigMap(solrQueryRequest, expandParams); + if (useExternalComponentNames) { + Map reMappedConfigMap = new NullKeyTolerantMap("children"); + for (Map.Entry e : configMap.entrySet()) { + reMappedConfigMap.put(toExternalComponentName(e.getKey()), e.getValue()); + } + configMap = reMappedConfigMap; + } + response.config = configMap; return response; + } @Override diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java index 504fe7ecb5e7..034a9965ef72 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java @@ -55,7 +55,10 @@ public void testGetConfigFromCore() throws Exception { assertTrue(response.config.containsKey("updateHandler")); assertTrue(response.config.containsKey("query")); assertTrue(response.config.containsKey("requestHandler")); - assertTrue(response.config.containsKey("searchComponent")); + + assertFalse(response.config.containsKey("searchComponent")); + assertTrue(response.config.containsKey("searchComponents")); + assertTrue(response.config.containsKey("updateProcessor")); } From 3379188e260c37172634711e506544ccb5f7f757 Mon Sep 17 00:00:00 2001 From: jaykay12 Date: Sat, 17 Oct 2026 04:16:10 +0530 Subject: [PATCH 2/5] tidy --- .../src/java/org/apache/solr/handler/SolrConfigHandler.java | 2 +- .../src/java/org/apache/solr/handler/admin/api/GetConfig.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java index 6c8c0db4250f..d6e460f7f2eb 100644 --- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java @@ -197,7 +197,7 @@ private void handleGET() { // v1 keeps internal section names (e.g. searchComponent); plurals are v2 only V2ApiUtils.squashIntoSolrResponseWithoutHeader( resp, - new GetConfig(req).getConfig(req.getParams().getBool("expandParams", false),false)); + new GetConfig(req).getConfig(req.getParams().getBool("expandParams", false), false)); } else { if (ConfigOverlay.NAME.equals(parts.get(1))) { V2ApiUtils.squashIntoSolrResponseWithoutHeader(resp, new GetConfig(req).getOverlay()); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java index 0b3e861f3a72..c8ddbfccea51 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java @@ -113,7 +113,6 @@ public ConfigInfoResponse getConfig(boolean expandParams, boolean useExternalCom } response.config = configMap; return response; - } @Override From b42395d05570a3a802ce92025a0bfc60c01b37e5 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 17 Oct 2026 11:06:46 -0400 Subject: [PATCH 3/5] Document the V2 full-config section-name pluralization The V1/V2 full-config output comparison only called out the children-key difference; add the searchComponent/queryResponseWriter pluralization this PR introduces, shown the same way as the existing children-key example (separate V1/V2 JSON output per tab). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RzzUgiebQ8ZhhgE2E7ZZU5 --- .../configuration-guide/pages/config-api.adoc | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc index 38981e7caf69..e26bf049beb8 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc @@ -64,6 +64,16 @@ A plugin's *unnamed* child elements - for example, the anonymous `` e ] }] ---- + +Top-level section names match the internal plugin type names used in `solrconfig.xml`, including `searchComponent` and `queryResponseWriter`: + +[source,json] +---- +{ + "searchComponent": {"elevator": {"class": "solr.QueryElevationComponent"}}, + "queryResponseWriter": {"xslt": {"class": "solr.XSLTResponseWriter"}} +} +---- ==== V2 API:: @@ -74,7 +84,9 @@ V2 API:: http://localhost:8983/api/collections/techproducts/config ---- -The response is the same merged configuration as the V1 API, with one difference: a plugin's unnamed child elements are grouped under a self-describing `children` key instead of an empty string, since Solr's V2 JSON serialization library does not allow empty-string keys: +The response is the same merged configuration as the V1 API, with two differences. + +First, a plugin's unnamed child elements are grouped under a self-describing `children` key instead of an empty string, since Solr's V2 JSON serialization library does not allow empty-string keys: [source,json] ---- @@ -87,6 +99,16 @@ The response is the same merged configuration as the V1 API, with one difference ] }] ---- + +Second, the `searchComponent` and `queryResponseWriter` sections are renamed to their pluralized forms, `searchComponents` and `queryResponseWriters`, matching the names used by the dedicated per-section endpoints described below: + +[source,json] +---- +{ + "searchComponents": {"elevator": {"class": "solr.QueryElevationComponent"}}, + "queryResponseWriters": {"xslt": {"class": "solr.XSLTResponseWriter"}} +} +---- ==== ====== From a20c8c1e98075cca7ba0c08d489d752cc75fcdaa Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 17 Oct 2026 11:10:26 -0400 Subject: [PATCH 4/5] Trim duplicate ref-guide examples from the pluralization note The new V1/V2 full-config diff duplicated the elevator/xslt example and explanation already given a few dozen lines down, where the per-section GET endpoints are documented. Drop the redundant JSON snippets and keep a single forward-pointing sentence instead. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RzzUgiebQ8ZhhgE2E7ZZU5 --- .../configuration-guide/pages/config-api.adoc | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc index e26bf049beb8..491207537888 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/config-api.adoc @@ -64,16 +64,6 @@ A plugin's *unnamed* child elements - for example, the anonymous `` e ] }] ---- - -Top-level section names match the internal plugin type names used in `solrconfig.xml`, including `searchComponent` and `queryResponseWriter`: - -[source,json] ----- -{ - "searchComponent": {"elevator": {"class": "solr.QueryElevationComponent"}}, - "queryResponseWriter": {"xslt": {"class": "solr.XSLTResponseWriter"}} -} ----- ==== V2 API:: @@ -100,15 +90,7 @@ First, a plugin's unnamed child elements are grouped under a self-describing `ch }] ---- -Second, the `searchComponent` and `queryResponseWriter` sections are renamed to their pluralized forms, `searchComponents` and `queryResponseWriters`, matching the names used by the dedicated per-section endpoints described below: - -[source,json] ----- -{ - "searchComponents": {"elevator": {"class": "solr.QueryElevationComponent"}}, - "queryResponseWriters": {"xslt": {"class": "solr.XSLTResponseWriter"}} -} ----- +Second, the `searchComponent` and `queryResponseWriter` sections are renamed to their pluralized forms, `searchComponents` and `queryResponseWriters`, as described below. ==== ====== From 7c6be74efebd72c63c654597213878c92bc061e0 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 17 Oct 2026 11:44:44 -0400 Subject: [PATCH 5/5] Fix TestSolrConfigHandler for the V2 full-config pluralization reqhandlertests() is shared between v1 and v2 harness runs (toggled randomly in @Before), and asserted the singular "searchComponent" key against the bare /config endpoint regardless of API version. Since GetConfig#getConfig now pluralizes that key under v2, the test failed whenever the random toggle picked v2 (reproduced with CI's exact seed 177EED04838EDD3C). Pick the expected key based on the harness's URL. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RzzUgiebQ8ZhhgE2E7ZZU5 --- .../org/apache/solr/core/TestSolrConfigHandler.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java index 4cb5b8889b6e..d18d99ed82c3 100644 --- a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java +++ b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java @@ -188,6 +188,11 @@ public static void runConfigCommandExpectFailure( } public static void reqhandlertests(RestTestHarness writeHarness) throws Exception { + // The full "/config" response pluralizes searchComponent -> searchComponents under the V2 + // API (see GetConfig#getConfig), but not under V1; the per-component endpoints used elsewhere + // in this test are unaffected since they already use the pluralized name. + String searchComponentKey = + writeHarness.getBaseURL().contains("/____v2/") ? "searchComponents" : "searchComponent"; String payload = "{\n" + "'create-requesthandler' : { 'name' : '/x', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy'}\n" @@ -332,7 +337,7 @@ public static void reqhandlertests(RestTestHarness writeHarness) throws Exceptio testForResponseElement( writeHarness, "/config", - asList("config", "searchComponent", "tc", "class"), + asList("config", searchComponentKey, "tc", "class"), "org.apache.solr.handler.component.TermsComponent", TIMEOUT_S); payload = @@ -343,14 +348,14 @@ public static void reqhandlertests(RestTestHarness writeHarness) throws Exceptio testForResponseElement( writeHarness, "/config", - asList("config", "searchComponent", "tc", "class"), + asList("config", searchComponentKey, "tc", "class"), "org.apache.solr.handler.component.TermVectorComponent", TIMEOUT_S); payload = "{\n" + "'delete-searchcomponent' : 'tc'" + "}"; runConfigCommand(writeHarness, "/config", payload); testForResponseElement( - writeHarness, "/config", asList("config", "searchComponent", "tc"), null, TIMEOUT_S); + writeHarness, "/config", asList("config", searchComponentKey, "tc"), null, TIMEOUT_S); // payload = @@ -444,7 +449,7 @@ public static void reqhandlertests(RestTestHarness writeHarness) throws Exceptio testForResponseElement( writeHarness, "/config", - asList("config", "searchComponent", "myspellcheck", "spellchecker", "class"), + asList("config", searchComponentKey, "myspellcheck", "spellchecker", "class"), "solr.DirectSolrSpellChecker", TIMEOUT_S);