You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2023/09/01 17:07:10 UTC

[solr] branch main updated: SOLR-16825: Migrate API definitions to submodule, pt 2 (#1866)

This is an automated email from the ASF dual-hosted git repository.

gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 9426902acb7 SOLR-16825: Migrate API definitions to submodule, pt 2 (#1866)
9426902acb7 is described below

commit 9426902acb7081a2e9a1fa29699c5286459e1365
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Fri Sep 1 13:07:03 2023 -0400

    SOLR-16825: Migrate API definitions to submodule, pt 2 (#1866)
    
    Extracting annotated interfaces for these APIs includes them in the SolrRequest-
    generation we now do in SolrJ.
---
 .../client/api/endpoint/AliasPropertyApis.java     |  95 ++++++++++++++++++
 .../solr/client/api/endpoint/ListAliasesApi.java   |  52 ++++++++++
 .../api/endpoint/ListCollectionBackupsApi.java     |  46 +++++++++
 .../client/api/endpoint/ListCollectionsApi.java    |  35 +++++++
 .../client/api/endpoint/ListConfigsetsApi.java     |  34 +++++++
 .../client/api/endpoint/ReloadCollectionApi.java   |  41 ++++++++
 .../client/api/model/CollectionBackupDetails.java  |  38 ++++++++
 .../apache/solr/client/api/model/Constants.java    |   3 +
 .../client/api/model/GetAliasByNameResponse.java   |  32 ++++++
 .../client/api/model/GetAliasPropertyResponse.java |  26 +++++
 .../api/model/GetAllAliasPropertiesResponse.java   |  27 ++++++
 .../solr/client/api/model/ListAliasesResponse.java |  28 ++++++
 .../api/model/ListCollectionBackupsResponse.java   |  25 +++++
 .../client/api/model/ListCollectionsResponse.java  |  25 +++++
 .../client/api/model/ListConfigsetsResponse.java   |  26 +++++
 .../api/model/ReloadCollectionRequestBody.java     |  27 ++++++
 .../model/UpdateAliasPropertiesRequestBody.java    |  32 ++++++
 .../api/model/UpdateAliasPropertyRequestBody.java  |  24 +++++
 .../solr/handler/admin/CollectionsHandler.java     |  29 +++---
 .../solr/handler/admin/ConfigSetsHandler.java      |   6 +-
 .../{AliasPropertyAPI.java => AliasProperty.java}  | 107 ++++-----------------
 .../api/{ListAliasesAPI.java => ListAliases.java}  |  59 ++----------
 ...nBackupsAPI.java => ListCollectionBackups.java} |  53 ++--------
 ...istCollectionsAPI.java => ListCollections.java} |  22 +----
 .../handler/admin/api/ReloadCollectionAPI.java     |  33 ++-----
 ...{ListConfigSetsAPI.java => ListConfigSets.java} |  29 ++----
 .../test/org/apache/solr/core/PluginBagTest.java   |   6 +-
 .../solr/handler/admin/api/ListAliasesAPITest.java |  10 +-
 .../handler/admin/api/ReloadCollectionAPITest.java |   7 +-
 .../handler/configsets/ListConfigSetsAPITest.java  |  21 ++--
 .../solrj/src/resources/java-template/api.mustache |   4 +-
 31 files changed, 712 insertions(+), 290 deletions(-)

diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java
new file mode 100644
index 00000000000..d993997d111
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.model.GetAliasPropertyResponse;
+import org.apache.solr.client.api.model.GetAllAliasPropertiesResponse;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UpdateAliasPropertiesRequestBody;
+import org.apache.solr.client.api.model.UpdateAliasPropertyRequestBody;
+
+/** V2 API definitions for managing and inspecting properties for collection aliases */
+@Path("/aliases/{aliasName}/properties")
+public interface AliasPropertyApis {
+
+  @GET
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Get properties for a collection alias.",
+      tags = {"alias-properties"})
+  GetAllAliasPropertiesResponse getAllAliasProperties(
+      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName)
+      throws Exception;
+
+  @GET
+  @Path("/{propName}")
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Get a specific property for a collection alias.",
+      tags = {"alias-properties"})
+  GetAliasPropertyResponse getAliasProperty(
+      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
+      @Parameter(description = "Property Name") @PathParam("propName") String propName)
+      throws Exception;
+
+  @PUT
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Update properties for a collection alias.",
+      tags = {"alias-properties"})
+  SolrJerseyResponse updateAliasProperties(
+      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
+      @RequestBody(description = "Properties that need to be updated", required = true)
+          UpdateAliasPropertiesRequestBody requestBody)
+      throws Exception;
+
+  @PUT
+  @Path("/{propName}")
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Update a specific property for a collection alias.",
+      tags = {"alias-properties"})
+  SolrJerseyResponse createOrUpdateAliasProperty(
+      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
+      @Parameter(description = "Property Name") @PathParam("propName") String propName,
+      @RequestBody(description = "Property value that needs to be updated", required = true)
+          UpdateAliasPropertyRequestBody requestBody)
+      throws Exception;
+
+  @DELETE
+  @Path("/{propName}")
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Delete a specific property for a collection alias.",
+      tags = {"alias-properties"})
+  SolrJerseyResponse deleteAliasProperty(
+      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
+      @Parameter(description = "Property Name") @PathParam("propName") String propName)
+      throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java
new file mode 100644
index 00000000000..eaeddf7bd2a
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.model.GetAliasByNameResponse;
+import org.apache.solr.client.api.model.ListAliasesResponse;
+
+/** V2 API definition for listing and inspecting collection aliases */
+@Path("/aliases")
+public interface ListAliasesApi {
+
+  @GET
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "List the existing collection aliases.",
+      tags = {"aliases"})
+  ListAliasesResponse getAliases() throws Exception;
+
+  @GET
+  @Path("/{aliasName}")
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Get details for a specific collection alias.",
+      tags = {"aliases"})
+  GetAliasByNameResponse getAliasByName(
+      @Parameter(description = "Alias name.", required = true) @PathParam("aliasName")
+          String aliasName)
+      throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java
new file mode 100644
index 00000000000..24701fb18cc
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import static org.apache.solr.client.api.model.Constants.BACKUP_LOCATION;
+import static org.apache.solr.client.api.model.Constants.BACKUP_REPOSITORY;
+import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2;
+
+import io.swagger.v3.oas.annotations.Operation;
+import java.io.IOException;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import org.apache.solr.client.api.model.ListCollectionBackupsResponse;
+
+/** V2 API definitions for collection-backup "listing". */
+@Path("/backups/{backupName}/versions")
+public interface ListCollectionBackupsApi {
+
+  @GET
+  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "List existing incremental backups at the specified location.",
+      tags = {"collection-backups"})
+  ListCollectionBackupsResponse listBackupsAtLocation(
+      @PathParam("backupName") String backupName,
+      @QueryParam(BACKUP_LOCATION) String location,
+      @QueryParam(BACKUP_REPOSITORY) String repositoryName)
+      throws IOException;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java
new file mode 100644
index 00000000000..fabb670a4b5
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import org.apache.solr.client.api.model.ListCollectionsResponse;
+
+@Path("/collections")
+public interface ListCollectionsApi {
+  @GET
+  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "List all collections in this Solr cluster",
+      tags = {"collections"})
+  ListCollectionsResponse listCollections();
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java
new file mode 100644
index 00000000000..c1e99b805a1
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import org.apache.solr.client.api.model.ListConfigsetsResponse;
+
+/** V2 API definition for listing configsets. */
+@Path("/cluster/configs")
+public interface ListConfigsetsApi {
+  @GET
+  @Produces({"application/json", "application/javabin"})
+  @Operation(
+      summary = "List the configsets available to Solr.",
+      tags = {"configsets"})
+  ListConfigsetsResponse listConfigSet() throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java
new file mode 100644
index 00000000000..39f27d2911d
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.model.ReloadCollectionRequestBody;
+import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
+
+/** V2 API definition for reloading collections. */
+@Path("/collections/{collectionName}/reload")
+public interface ReloadCollectionApi {
+  @POST
+  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Operation(
+      summary = "Reload all cores in the specified collection.",
+      tags = {"collections"})
+  SubResponseAccumulatingJerseyResponse reloadCollection(
+      @PathParam("collectionName") String collectionName, ReloadCollectionRequestBody requestBody)
+      throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/CollectionBackupDetails.java b/solr/api/src/java/org/apache/solr/client/api/model/CollectionBackupDetails.java
new file mode 100644
index 00000000000..a46529baab4
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/CollectionBackupDetails.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import static org.apache.solr.client.api.model.Constants.COLL_CONF;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+
+public class CollectionBackupDetails {
+  @JsonProperty public Integer backupId;
+  @JsonProperty public String indexVersion;
+  @JsonProperty public String startTime;
+  @JsonProperty public String endTime;
+  @JsonProperty public Integer indexFileCount;
+  @JsonProperty public Double indexSizeMB;
+
+  @JsonProperty public Map<String, String> shardBackupIds;
+
+  @JsonProperty(COLL_CONF)
+  public String configsetName;
+
+  @JsonProperty public String collectionAlias;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/Constants.java b/solr/api/src/java/org/apache/solr/client/api/model/Constants.java
index e6ad827756f..0992c2c3a17 100644
--- a/solr/api/src/java/org/apache/solr/client/api/model/Constants.java
+++ b/solr/api/src/java/org/apache/solr/client/api/model/Constants.java
@@ -48,4 +48,7 @@ public class Constants {
   public static final String DELETE_INSTANCE_DIR = "deleteInstanceDir";
 
   public static final String ONLY_IF_DOWN = "onlyIfDown";
+
+  /** The name of the config set to be used for a collection */
+  public static final String COLL_CONF = "collection.configName";
 }
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/GetAliasByNameResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/GetAliasByNameResponse.java
new file mode 100644
index 00000000000..df0498d9f12
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/GetAliasByNameResponse.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import java.util.Map;
+
+public class GetAliasByNameResponse extends SolrJerseyResponse {
+  @JsonProperty("name")
+  public String alias;
+
+  @JsonProperty("collections")
+  public List<String> collections;
+
+  @JsonProperty("properties")
+  public Map<String, String> properties;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/GetAliasPropertyResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/GetAliasPropertyResponse.java
new file mode 100644
index 00000000000..93e62ba04c6
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/GetAliasPropertyResponse.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+public class GetAliasPropertyResponse extends SolrJerseyResponse {
+  @JsonProperty("value")
+  @Schema(description = "Property value.")
+  public String value;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/GetAllAliasPropertiesResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/GetAllAliasPropertiesResponse.java
new file mode 100644
index 00000000000..17b93d45471
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/GetAllAliasPropertiesResponse.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Map;
+
+public class GetAllAliasPropertiesResponse extends SolrJerseyResponse {
+  @JsonProperty("properties")
+  @Schema(description = "Properties and values associated with alias.")
+  public Map<String, String> properties;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ListAliasesResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ListAliasesResponse.java
new file mode 100644
index 00000000000..3d9c93af85e
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ListAliasesResponse.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+
+public class ListAliasesResponse extends SolrJerseyResponse {
+  @JsonProperty("aliases")
+  public Map<String, String> aliases;
+
+  @JsonProperty("properties")
+  public Map<String, Map<String, String>> properties;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionBackupsResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionBackupsResponse.java
new file mode 100644
index 00000000000..038a3df2ff4
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionBackupsResponse.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+
+public class ListCollectionBackupsResponse extends SolrJerseyResponse {
+  @JsonProperty public String collection;
+  @JsonProperty public List<CollectionBackupDetails> backups;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionsResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionsResponse.java
new file mode 100644
index 00000000000..17bf44c44ec
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ListCollectionsResponse.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+
+public class ListCollectionsResponse extends SolrJerseyResponse {
+  @JsonProperty("collections")
+  public List<String> collections;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ListConfigsetsResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ListConfigsetsResponse.java
new file mode 100644
index 00000000000..09b99dfbdc9
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ListConfigsetsResponse.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+
+public class ListConfigsetsResponse extends SolrJerseyResponse {
+
+  @JsonProperty("configSets")
+  public List<String> configSets;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ReloadCollectionRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/ReloadCollectionRequestBody.java
new file mode 100644
index 00000000000..287e5453381
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ReloadCollectionRequestBody.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import static org.apache.solr.client.api.model.Constants.ASYNC;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+// TODO Is it worth having this in a request body, or should we just make it a query param?
+public class ReloadCollectionRequestBody {
+  @JsonProperty(ASYNC)
+  public String async;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertiesRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertiesRequestBody.java
new file mode 100644
index 00000000000..de6a48a0a50
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertiesRequestBody.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Map;
+
+public class UpdateAliasPropertiesRequestBody {
+
+  @Schema(description = "Properties and values to be updated on alias.")
+  @JsonProperty(value = "properties", required = true)
+  public Map<String, Object> properties;
+
+  @Schema(description = "Request ID to track this action which will be processed asynchronously.")
+  @JsonProperty("async")
+  public String async;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertyRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertyRequestBody.java
new file mode 100644
index 00000000000..a7a82536b71
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/UpdateAliasPropertyRequestBody.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class UpdateAliasPropertyRequestBody {
+  @JsonProperty(required = true)
+  public Object value;
+}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index 732d7eb03c2..b1949c993a1 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -124,6 +124,7 @@ import org.apache.solr.api.Api;
 import org.apache.solr.api.JerseyResource;
 import org.apache.solr.client.api.model.AddReplicaPropertyRequestBody;
 import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UpdateAliasPropertiesRequestBody;
 import org.apache.solr.client.solrj.SolrResponse;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.response.RequestStatusState;
@@ -164,7 +165,7 @@ import org.apache.solr.core.snapshots.SolrSnapshotManager;
 import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.handler.admin.api.AddReplicaProperty;
 import org.apache.solr.handler.admin.api.AdminAPIBase;
-import org.apache.solr.handler.admin.api.AliasPropertyAPI;
+import org.apache.solr.handler.admin.api.AliasProperty;
 import org.apache.solr.handler.admin.api.BalanceReplicasAPI;
 import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI;
 import org.apache.solr.handler.admin.api.CollectionPropertyAPI;
@@ -185,10 +186,10 @@ import org.apache.solr.handler.admin.api.DeleteReplicaProperty;
 import org.apache.solr.handler.admin.api.DeleteShardAPI;
 import org.apache.solr.handler.admin.api.ForceLeaderAPI;
 import org.apache.solr.handler.admin.api.InstallShardDataAPI;
-import org.apache.solr.handler.admin.api.ListAliasesAPI;
-import org.apache.solr.handler.admin.api.ListCollectionBackupsAPI;
+import org.apache.solr.handler.admin.api.ListAliases;
+import org.apache.solr.handler.admin.api.ListCollectionBackups;
 import org.apache.solr.handler.admin.api.ListCollectionSnapshotsAPI;
-import org.apache.solr.handler.admin.api.ListCollectionsAPI;
+import org.apache.solr.handler.admin.api.ListCollections;
 import org.apache.solr.handler.admin.api.MigrateDocsAPI;
 import org.apache.solr.handler.admin.api.MigrateReplicasAPI;
 import org.apache.solr.handler.admin.api.ModifyCollectionAPI;
@@ -640,11 +641,10 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
         (req, rsp, h) -> {
           String name = req.getParams().required().get(NAME);
           Map<String, Object> properties = collectToMap(req.getParams(), "property");
-          AliasPropertyAPI.UpdateAliasPropertiesRequestBody requestBody =
-              new AliasPropertyAPI.UpdateAliasPropertiesRequestBody();
+          final var requestBody = new UpdateAliasPropertiesRequestBody();
           requestBody.properties = properties;
           requestBody.async = req.getParams().get(ASYNC);
-          final AliasPropertyAPI aliasPropertyAPI = new AliasPropertyAPI(h.coreContainer, req, rsp);
+          final AliasProperty aliasPropertyAPI = new AliasProperty(h.coreContainer, req, rsp);
           final SolrJerseyResponse getAliasesResponse =
               aliasPropertyAPI.updateAliasProperties(name, requestBody);
           V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, getAliasesResponse);
@@ -655,7 +655,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
     LISTALIASES_OP(
         LISTALIASES,
         (req, rsp, h) -> {
-          final ListAliasesAPI getAliasesAPI = new ListAliasesAPI(h.coreContainer, req, rsp);
+          final ListAliases getAliasesAPI = new ListAliases(h.coreContainer, req, rsp);
           final SolrJerseyResponse getAliasesResponse = getAliasesAPI.getAliases();
           V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, getAliasesResponse);
           return null;
@@ -965,8 +965,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
     LIST_OP(
         LIST,
         (req, rsp, h) -> {
-          final ListCollectionsAPI listCollectionsAPI =
-              new ListCollectionsAPI(h.coreContainer, req, rsp);
+          final ListCollections listCollectionsAPI = new ListCollections(h.coreContainer, req, rsp);
           final SolrJerseyResponse listCollectionsResponse = listCollectionsAPI.listCollections();
           V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, listCollectionsResponse);
           return null;
@@ -1103,7 +1102,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
         LISTBACKUP,
         (req, rsp, h) -> {
           req.getParams().required().check(NAME);
-          ListCollectionBackupsAPI.invokeFromV1Params(h.coreContainer, req, rsp);
+          ListCollectionBackups.invokeFromV1Params(h.coreContainer, req, rsp);
           return null;
         }),
     CREATESNAPSHOT_OP(
@@ -1378,8 +1377,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
         DeleteShardAPI.class,
         ForceLeaderAPI.class,
         InstallShardDataAPI.class,
-        ListCollectionsAPI.class,
-        ListCollectionBackupsAPI.class,
+        ListCollections.class,
+        ListCollectionBackups.class,
         ReloadCollectionAPI.class,
         RenameCollectionAPI.class,
         ReplaceNodeAPI.class,
@@ -1389,8 +1388,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
         SyncShardAPI.class,
         CollectionPropertyAPI.class,
         DeleteNode.class,
-        ListAliasesAPI.class,
-        AliasPropertyAPI.class,
+        ListAliases.class,
+        AliasProperty.class,
         ListCollectionSnapshotsAPI.class,
         CreateCollectionSnapshotAPI.class,
         DeleteCollectionSnapshot.class);
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
index 96015b2486e..e5bd2945b43 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandler.java
@@ -43,7 +43,7 @@ import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.handler.api.V2ApiUtils;
 import org.apache.solr.handler.configsets.CreateConfigSetAPI;
 import org.apache.solr.handler.configsets.DeleteConfigSetAPI;
-import org.apache.solr.handler.configsets.ListConfigSetsAPI;
+import org.apache.solr.handler.configsets.ListConfigSets;
 import org.apache.solr.handler.configsets.UploadConfigSetAPI;
 import org.apache.solr.handler.configsets.UploadConfigSetFileAPI;
 import org.apache.solr.request.DelegatingSolrQueryRequest;
@@ -142,7 +142,7 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
         }
         break;
       case LIST:
-        final ListConfigSetsAPI listConfigSetsAPI = new ListConfigSetsAPI(coreContainer);
+        final ListConfigSets listConfigSetsAPI = new ListConfigSets(coreContainer);
         V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, listConfigSetsAPI.listConfigSet());
         break;
       case CREATE:
@@ -217,7 +217,7 @@ public class ConfigSetsHandler extends RequestHandlerBase implements PermissionN
 
   @Override
   public Collection<Class<? extends JerseyResource>> getJerseyResources() {
-    return List.of(ListConfigSetsAPI.class);
+    return List.of(ListConfigSets.class);
   }
 
   @Override
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/AliasPropertyAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/AliasProperty.java
similarity index 62%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/AliasPropertyAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/AliasProperty.java
index baeb6ddc7ac..1184751cb9a 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/AliasPropertyAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/AliasProperty.java
@@ -16,7 +16,6 @@
  */
 package org.apache.solr.handler.admin.api;
 
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
 import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
 import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
 import static org.apache.solr.common.params.CommonParams.NAME;
@@ -24,22 +23,15 @@ import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTIO
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_READ_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
 import java.util.HashMap;
 import java.util.Map;
 import javax.inject.Inject;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.endpoint.AliasPropertyApis;
+import org.apache.solr.client.api.model.GetAliasPropertyResponse;
+import org.apache.solr.client.api.model.GetAllAliasPropertiesResponse;
 import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.model.UpdateAliasPropertiesRequestBody;
+import org.apache.solr.client.api.model.UpdateAliasPropertyRequestBody;
 import org.apache.solr.client.solrj.SolrResponse;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.Aliases;
@@ -48,32 +40,24 @@ import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CollectionParams;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.handler.admin.CollectionsHandler;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
 import org.apache.solr.jersey.PermissionName;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 
 /** V2 APIs for managing and inspecting properties for collection aliases */
-@Path("/aliases/{aliasName}/properties")
-public class AliasPropertyAPI extends AdminAPIBase {
+public class AliasProperty extends AdminAPIBase implements AliasPropertyApis {
 
   @Inject
-  public AliasPropertyAPI(
+  public AliasProperty(
       CoreContainer coreContainer,
       SolrQueryRequest solrQueryRequest,
       SolrQueryResponse solrQueryResponse) {
     super(coreContainer, solrQueryRequest, solrQueryResponse);
   }
 
-  @GET
+  @Override
   @PermissionName(COLL_READ_PERM)
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
-  @Operation(
-      summary = "Get properties for a collection alias.",
-      tags = {"aliases"})
-  public GetAllAliasPropertiesResponse getAllAliasProperties(
-      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName)
-      throws Exception {
+  public GetAllAliasPropertiesResponse getAllAliasProperties(String aliasName) throws Exception {
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
     final GetAllAliasPropertiesResponse response =
@@ -88,16 +72,9 @@ public class AliasPropertyAPI extends AdminAPIBase {
     return response;
   }
 
-  @GET
-  @Path("/{propName}")
+  @Override
   @PermissionName(COLL_READ_PERM)
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
-  @Operation(
-      summary = "Get a specific property for a collection alias.",
-      tags = {"aliases"})
-  public GetAliasPropertyResponse getAliasProperty(
-      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
-      @Parameter(description = "Property Name") @PathParam("propName") String propName)
+  public GetAliasPropertyResponse getAliasProperty(String aliasName, String propName)
       throws Exception {
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
@@ -124,17 +101,10 @@ public class AliasPropertyAPI extends AdminAPIBase {
     return zkStateReader.getAliases();
   }
 
-  @PUT
+  @Override
   @PermissionName(COLL_EDIT_PERM)
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
-  @Operation(
-      summary = "Update properties for a collection alias.",
-      tags = {"aliases"})
   public SolrJerseyResponse updateAliasProperties(
-      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
-      @RequestBody(description = "Properties that need to be updated", required = true)
-          UpdateAliasPropertiesRequestBody requestBody)
-      throws Exception {
+      String aliasName, UpdateAliasPropertiesRequestBody requestBody) throws Exception {
 
     if (requestBody == null) {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing required request body");
@@ -147,18 +117,10 @@ public class AliasPropertyAPI extends AdminAPIBase {
     return response;
   }
 
-  @PUT
-  @Path("/{propName}")
+  @Override
   @PermissionName(COLL_EDIT_PERM)
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
-  @Operation(
-      summary = "Update a specific property for a collection alias.",
-      tags = {"aliases"})
   public SolrJerseyResponse createOrUpdateAliasProperty(
-      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
-      @Parameter(description = "Property Name") @PathParam("propName") String propName,
-      @RequestBody(description = "Property value that needs to be updated", required = true)
-          UpdateAliasPropertyRequestBody requestBody)
+      String aliasName, String propName, UpdateAliasPropertyRequestBody requestBody)
       throws Exception {
     if (requestBody == null) {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing required request body");
@@ -171,16 +133,9 @@ public class AliasPropertyAPI extends AdminAPIBase {
     return response;
   }
 
-  @DELETE
-  @Path("/{propName}")
+  @Override
   @PermissionName(COLL_EDIT_PERM)
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
-  @Operation(
-      summary = "Delete a specific property for a collection alias.",
-      tags = {"aliases"})
-  public SolrJerseyResponse deleteAliasProperty(
-      @Parameter(description = "Alias Name") @PathParam("aliasName") String aliasName,
-      @Parameter(description = "Property Name") @PathParam("propName") String propName)
+  public SolrJerseyResponse deleteAliasProperty(String aliasName, String propName)
       throws Exception {
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
@@ -233,32 +188,4 @@ public class AliasPropertyAPI extends AdminAPIBase {
     }
     return new ZkNodeProps(remoteMessage);
   }
-
-  public static class UpdateAliasPropertiesRequestBody implements JacksonReflectMapWriter {
-
-    @Schema(description = "Properties and values to be updated on alias.")
-    @JsonProperty(value = "properties", required = true)
-    public Map<String, Object> properties;
-
-    @Schema(description = "Request ID to track this action which will be processed asynchronously.")
-    @JsonProperty("async")
-    public String async;
-  }
-
-  public static class UpdateAliasPropertyRequestBody implements JacksonReflectMapWriter {
-    @JsonProperty(required = true)
-    public Object value;
-  }
-
-  public static class GetAllAliasPropertiesResponse extends SolrJerseyResponse {
-    @JsonProperty("properties")
-    @Schema(description = "Properties and values associated with alias.")
-    public Map<String, String> properties;
-  }
-
-  public static class GetAliasPropertyResponse extends SolrJerseyResponse {
-    @JsonProperty("value")
-    @Schema(description = "Property value.")
-    public String value;
-  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ListAliasesAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ListAliases.java
similarity index 65%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/ListAliasesAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/ListAliases.java
index 0e2626e9668..d8995ce16ae 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ListAliasesAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ListAliases.java
@@ -16,22 +16,15 @@
  */
 package org.apache.solr.handler.admin.api;
 
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_READ_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.endpoint.ListAliasesApi;
+import org.apache.solr.client.api.model.GetAliasByNameResponse;
+import org.apache.solr.client.api.model.ListAliasesResponse;
 import org.apache.solr.common.cloud.Aliases;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
@@ -39,12 +32,11 @@ import org.apache.solr.jersey.PermissionName;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 
-/** V2 APIs for managing and inspecting collection aliases */
-@Path("/aliases")
-public class ListAliasesAPI extends AdminAPIBase {
+/** V2 API implementation for listing and inspecting collection aliases */
+public class ListAliases extends AdminAPIBase implements ListAliasesApi {
 
   @Inject
-  public ListAliasesAPI(
+  public ListAliases(
       CoreContainer coreContainer,
       SolrQueryRequest solrQueryRequest,
       SolrQueryResponse solrQueryResponse) {
@@ -57,12 +49,8 @@ public class ListAliasesAPI extends AdminAPIBase {
    * <p>This API <code>GET /api/aliases</code> is analogous to the v1 <code>GET /api/cluster/aliases
    * </code> API.
    */
-  @GET
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Override
   @PermissionName(COLL_READ_PERM)
-  @Operation(
-      summary = "List the existing collection aliases.",
-      tags = {"aliases"})
   public ListAliasesResponse getAliases() throws Exception {
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
@@ -86,17 +74,9 @@ public class ListAliasesAPI extends AdminAPIBase {
     return response;
   }
 
-  @GET
-  @Path("/{aliasName}")
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Override
   @PermissionName(COLL_READ_PERM)
-  @Operation(
-      summary = "Get details for a specific collection alias.",
-      tags = {"aliases"})
-  public GetAliasByNameResponse getAliasByName(
-      @Parameter(description = "Alias name.", required = true) @PathParam("aliasName")
-          String aliasName)
-      throws Exception {
+  public GetAliasByNameResponse getAliasByName(String aliasName) throws Exception {
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
     final GetAliasByNameResponse response = instantiateJerseyResponse(GetAliasByNameResponse.class);
@@ -119,25 +99,4 @@ public class ListAliasesAPI extends AdminAPIBase {
 
     return zkStateReader.getAliases();
   }
-
-  /** Response for {@link ListAliasesAPI#getAliases()}. */
-  public static class ListAliasesResponse extends SolrJerseyResponse {
-    @JsonProperty("aliases")
-    public Map<String, String> aliases;
-
-    @JsonProperty("properties")
-    public Map<String, Map<String, String>> properties;
-  }
-
-  /** Response for {@link ListAliasesAPI#getAliasByName(String)}. */
-  public static class GetAliasByNameResponse extends SolrJerseyResponse {
-    @JsonProperty("name")
-    public String alias;
-
-    @JsonProperty("collections")
-    public List<String> collections;
-
-    @JsonProperty("properties")
-    public Map<String, String> properties;
-  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackupsAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackups.java
similarity index 70%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackupsAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackups.java
index 3ec3c599e0d..859e0e38941 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackupsAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionBackups.java
@@ -17,15 +17,12 @@
 
 package org.apache.solr.handler.admin.api;
 
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
-import static org.apache.solr.common.params.CollectionAdminParams.COLL_CONF;
 import static org.apache.solr.common.params.CoreAdminParams.BACKUP_ID;
 import static org.apache.solr.common.params.CoreAdminParams.BACKUP_LOCATION;
 import static org.apache.solr.common.params.CoreAdminParams.BACKUP_REPOSITORY;
 import static org.apache.solr.common.params.CoreAdminParams.NAME;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.net.URI;
@@ -33,12 +30,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.endpoint.ListCollectionBackupsApi;
+import org.apache.solr.client.api.model.CollectionBackupDetails;
+import org.apache.solr.client.api.model.ListCollectionBackupsResponse;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.core.CoreContainer;
@@ -46,23 +40,22 @@ import org.apache.solr.core.backup.BackupFilePaths;
 import org.apache.solr.core.backup.BackupId;
 import org.apache.solr.core.backup.BackupProperties;
 import org.apache.solr.handler.api.V2ApiUtils;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
 import org.apache.solr.jersey.PermissionName;
 import org.apache.solr.jersey.SolrJacksonMapper;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 
 /**
- * V2 API definitions for collection-backup "listing".
+ * V2 API implementations for collection-backup "listing".
  *
  * <p>These APIs are equivalent to the v1 '/admin/collections?action=LISTBACKUP' command.
  */
-public class ListCollectionBackupsAPI extends BackupAPIBase {
+public class ListCollectionBackups extends BackupAPIBase implements ListCollectionBackupsApi {
 
   private final ObjectMapper objectMapper;
 
   @Inject
-  public ListCollectionBackupsAPI(
+  public ListCollectionBackups(
       CoreContainer coreContainer,
       SolrQueryRequest solrQueryRequest,
       SolrQueryResponse solrQueryResponse) {
@@ -76,22 +69,17 @@ public class ListCollectionBackupsAPI extends BackupAPIBase {
     final SolrParams v1Params = req.getParams();
     v1Params.required().check(CommonParams.NAME);
 
-    final var listApi = new ListCollectionBackupsAPI(coreContainer, req, rsp);
+    final var listApi = new ListCollectionBackups(coreContainer, req, rsp);
     V2ApiUtils.squashIntoSolrResponseWithoutHeader(
         rsp,
         listApi.listBackupsAtLocation(
             v1Params.get(NAME), v1Params.get(BACKUP_LOCATION), v1Params.get(BACKUP_REPOSITORY)));
   }
 
-  @Path("/backups/{backupName}/versions")
-  @GET
-  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+  @Override
   @PermissionName(COLL_EDIT_PERM)
   public ListCollectionBackupsResponse listBackupsAtLocation(
-      @PathParam("backupName") String backupName,
-      @QueryParam(BACKUP_LOCATION) String location,
-      @QueryParam(BACKUP_REPOSITORY) String repositoryName)
-      throws IOException {
+      String backupName, String location, String repositoryName) throws IOException {
     final var response = instantiateJerseyResponse(ListCollectionBackupsResponse.class);
     recordCollectionForLogAndTracing(null, solrQueryRequest);
 
@@ -123,27 +111,4 @@ public class ListCollectionBackupsAPI extends BackupAPIBase {
     }
     return response;
   }
-
-  public static class ListCollectionBackupsResponse extends SolrJerseyResponse {
-    @JsonProperty public String collection;
-    @JsonProperty public List<CollectionBackupDetails> backups;
-  }
-
-  // TODO Merge with CreateCollectionBackupAPI.CollectionBackupDetails, which seems very
-  // conceptually similar...
-  public static class CollectionBackupDetails implements JacksonReflectMapWriter {
-    @JsonProperty public Integer backupId;
-    @JsonProperty public String indexVersion;
-    @JsonProperty public String startTime;
-    @JsonProperty public String endTime;
-    @JsonProperty public Integer indexFileCount;
-    @JsonProperty public Double indexSizeMB;
-
-    @JsonProperty public Map<String, String> shardBackupIds;
-
-    @JsonProperty(COLL_CONF)
-    public String configsetName;
-
-    @JsonProperty public String collectionAlias;
-  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionsAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollections.java
similarity index 75%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionsAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/ListCollections.java
index e03b05a6f70..2f08a7323ac 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollectionsAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ListCollections.java
@@ -17,19 +17,15 @@
 
 package org.apache.solr.handler.admin.api;
 
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_READ_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.endpoint.ListCollectionsApi;
+import org.apache.solr.client.api.model.ListCollectionsResponse;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.jersey.PermissionName;
@@ -41,17 +37,14 @@ import org.apache.solr.response.SolrQueryResponse;
  *
  * <p>This API (GET /v2/collections) is equivalent to the v1 /admin/collections?action=LIST command
  */
-@Path("/collections")
-public class ListCollectionsAPI extends AdminAPIBase {
+public class ListCollections extends AdminAPIBase implements ListCollectionsApi {
 
   @Inject
-  public ListCollectionsAPI(
-      CoreContainer coreContainer, SolrQueryRequest req, SolrQueryResponse rsp) {
+  public ListCollections(CoreContainer coreContainer, SolrQueryRequest req, SolrQueryResponse rsp) {
     super(coreContainer, req, rsp);
   }
 
-  @GET
-  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+  @Override
   @PermissionName(COLL_READ_PERM)
   public ListCollectionsResponse listCollections() {
     final ListCollectionsResponse response =
@@ -67,9 +60,4 @@ public class ListCollectionsAPI extends AdminAPIBase {
 
     return response;
   }
-
-  public static class ListCollectionsResponse extends SolrJerseyResponse {
-    @JsonProperty("collections")
-    public List<String> collections;
-  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCollectionAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCollectionAPI.java
index 22c2abdaca3..be80062d87a 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCollectionAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ReloadCollectionAPI.java
@@ -16,29 +16,23 @@
  */
 package org.apache.solr.handler.admin.api;
 
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
 import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
 import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import java.lang.invoke.MethodHandles;
 import java.util.HashMap;
 import java.util.Map;
 import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.endpoint.ReloadCollectionApi;
+import org.apache.solr.client.api.model.ReloadCollectionRequestBody;
 import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.params.CollectionParams;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.handler.api.V2ApiUtils;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
 import org.apache.solr.jersey.PermissionName;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
@@ -46,13 +40,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * V2 API for reloading collections.
+ * V2 API implementation for reloading collections.
  *
  * <p>The new API (POST /v2/collections/collectionName/reload {...}) is analogous to the v1
  * /admin/collections?action=RELOAD command.
  */
-@Path("/collections/{collectionName}/reload")
-public class ReloadCollectionAPI extends AdminAPIBase {
+public class ReloadCollectionAPI extends AdminAPIBase implements ReloadCollectionApi {
 
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -64,12 +57,10 @@ public class ReloadCollectionAPI extends AdminAPIBase {
     super(coreContainer, solrQueryRequest, solrQueryResponse);
   }
 
-  @POST
-  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+  @Override
   @PermissionName(COLL_EDIT_PERM)
   public SubResponseAccumulatingJerseyResponse reloadCollection(
-      @PathParam("collectionName") String collectionName, ReloadCollectionRequestBody requestBody)
-      throws Exception {
+      String collectionName, ReloadCollectionRequestBody requestBody) throws Exception {
     final var response = instantiateJerseyResponse(SubResponseAccumulatingJerseyResponse.class);
     ensureRequiredParameterProvided(COLLECTION_PROP, collectionName);
     fetchAndValidateZooKeeperAwareCoreContainer();
@@ -80,7 +71,7 @@ public class ReloadCollectionAPI extends AdminAPIBase {
         response,
         CollectionParams.CollectionAction.RELOAD,
         remoteMessage,
-        requestBody != null ? requestBody.asyncId : null);
+        requestBody != null ? requestBody.async : null);
     return response;
   }
 
@@ -90,7 +81,7 @@ public class ReloadCollectionAPI extends AdminAPIBase {
     remoteMessage.put(QUEUE_OPERATION, CollectionParams.CollectionAction.RELOAD.toLower());
     remoteMessage.put(NAME, collectionName);
     if (requestBody != null) {
-      insertIfNotNull(remoteMessage, ASYNC, requestBody.asyncId);
+      insertIfNotNull(remoteMessage, ASYNC, requestBody.async);
     }
 
     return new ZkNodeProps(remoteMessage);
@@ -103,15 +94,9 @@ public class ReloadCollectionAPI extends AdminAPIBase {
     final var params = request.getParams();
     params.required().check(NAME);
     final var requestBody = new ReloadCollectionRequestBody();
-    requestBody.asyncId = params.get(ASYNC); // Note, 'async' may or may not have been provided.
+    requestBody.async = params.get(ASYNC); // Note, 'async' may or may not have been provided.
 
     V2ApiUtils.squashIntoSolrResponseWithoutHeader(
         response, api.reloadCollection(params.get(NAME), requestBody));
   }
-
-  // TODO Is it worth having this in a request body, or should we just make it a query param?
-  public static class ReloadCollectionRequestBody implements JacksonReflectMapWriter {
-    @JsonProperty(ASYNC)
-    public String asyncId;
-  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSetsAPI.java b/solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSets.java
similarity index 66%
rename from solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSetsAPI.java
rename to solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSets.java
index 58dcdfec5e9..c3403eb3af8 100644
--- a/solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSetsAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/configsets/ListConfigSets.java
@@ -18,53 +18,36 @@ package org.apache.solr.handler.configsets;
 
 import static org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.Operation;
-import java.util.List;
 import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import org.apache.solr.api.JerseyResource;
-import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.endpoint.ListConfigsetsApi;
+import org.apache.solr.client.api.model.ListConfigsetsResponse;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.jersey.PermissionName;
 
 /**
- * V2 API for adding or updating a single file within a configset.
+ * V2 API implementation for listing all available configsets.
  *
  * <p>This API (GET /v2/cluster/configs) is analogous to the v1 /admin/configs?action=LIST command.
  */
-@Path("/cluster/configs")
-public class ListConfigSetsAPI extends JerseyResource {
+public class ListConfigSets extends JerseyResource implements ListConfigsetsApi {
 
   @Context public HttpHeaders headers;
 
   private final CoreContainer coreContainer;
 
   @Inject
-  public ListConfigSetsAPI(CoreContainer coreContainer) {
+  public ListConfigSets(CoreContainer coreContainer) {
     this.coreContainer = coreContainer;
   }
 
-  @GET
-  @Produces({"application/json", "application/javabin"})
-  @Operation(
-      summary = "List the configsets available to Solr.",
-      tags = {"configset"})
+  @Override
   @PermissionName(CONFIG_READ_PERM)
   public ListConfigsetsResponse listConfigSet() throws Exception {
     final ListConfigsetsResponse response = instantiateJerseyResponse(ListConfigsetsResponse.class);
     response.configSets = coreContainer.getConfigSetService().listConfigs();
     return response;
   }
-
-  /** Response body POJO for the {@link ListConfigSetsAPI} resource. */
-  public static class ListConfigsetsResponse extends SolrJerseyResponse {
-
-    @JsonProperty("configSets")
-    public List<String> configSets;
-  }
 }
diff --git a/solr/core/src/test/org/apache/solr/core/PluginBagTest.java b/solr/core/src/test/org/apache/solr/core/PluginBagTest.java
index bfc585b8840..d3831489edb 100644
--- a/solr/core/src/test/org/apache/solr/core/PluginBagTest.java
+++ b/solr/core/src/test/org/apache/solr/core/PluginBagTest.java
@@ -28,7 +28,7 @@ import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.handler.admin.ConfigSetsHandler;
 import org.apache.solr.handler.admin.api.CollectionPropertyAPI;
 import org.apache.solr.handler.component.SearchComponent;
-import org.apache.solr.handler.configsets.ListConfigSetsAPI;
+import org.apache.solr.handler.configsets.ListConfigSets;
 import org.apache.solr.jersey.APIConfigProvider;
 import org.apache.solr.jersey.APIConfigProvider.APIConfig;
 import org.apache.solr.jersey.APIConfigProviderBinder;
@@ -95,12 +95,12 @@ public class PluginBagTest extends SolrTestCaseJ4 {
   public void testRegistersJerseyResourcesAssociatedWithRequestHandlers() {
     final PluginBag<SolrRequestHandler> handlerPluginBag =
         new PluginBag<>(SolrRequestHandler.class, null);
-    assertFalse(handlerPluginBag.getJerseyEndpoints().isRegistered(ListConfigSetsAPI.class));
+    assertFalse(handlerPluginBag.getJerseyEndpoints().isRegistered(ListConfigSets.class));
 
     handlerPluginBag.put("/foo", new ConfigSetsHandler(coreContainer));
     final ResourceConfig config = handlerPluginBag.getJerseyEndpoints();
 
-    assertTrue(handlerPluginBag.getJerseyEndpoints().isRegistered(ListConfigSetsAPI.class));
+    assertTrue(handlerPluginBag.getJerseyEndpoints().isRegistered(ListConfigSets.class));
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ListAliasesAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ListAliasesAPITest.java
index 2a6607c40b6..9939217b4b0 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/ListAliasesAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ListAliasesAPITest.java
@@ -23,20 +23,20 @@ import io.opentelemetry.api.trace.Span;
 import java.util.List;
 import java.util.Map;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.GetAliasByNameResponse;
+import org.apache.solr.client.api.model.ListAliasesResponse;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.cloud.Aliases;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.cloud.ZkStateReader.AliasesManager;
 import org.apache.solr.core.CoreContainer;
-import org.apache.solr.handler.admin.api.ListAliasesAPI.GetAliasByNameResponse;
-import org.apache.solr.handler.admin.api.ListAliasesAPI.ListAliasesResponse;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-/** Unit tests for {@link ListAliasesAPI} */
+/** Unit tests for {@link ListAliases} */
 public class ListAliasesAPITest extends SolrTestCaseJ4 {
 
   private CoreContainer mockCoreContainer;
@@ -44,7 +44,7 @@ public class ListAliasesAPITest extends SolrTestCaseJ4 {
   private SolrQueryRequest mockQueryRequest;
   private SolrQueryResponse queryResponse;
 
-  private ListAliasesAPI getAliasesAPI;
+  private ListAliases getAliasesAPI;
 
   @BeforeClass
   public static void ensureWorkingMockito() {
@@ -70,7 +70,7 @@ public class ListAliasesAPITest extends SolrTestCaseJ4 {
     when(mockQueryRequest.getSpan()).thenReturn(Span.getInvalid());
     queryResponse = new SolrQueryResponse();
 
-    getAliasesAPI = new ListAliasesAPI(mockCoreContainer, mockQueryRequest, queryResponse);
+    getAliasesAPI = new ListAliases(mockCoreContainer, mockQueryRequest, queryResponse);
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ReloadCollectionAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ReloadCollectionAPITest.java
index e7534dc0c1a..5900fece7a4 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/ReloadCollectionAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ReloadCollectionAPITest.java
@@ -22,6 +22,7 @@ import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
 import static org.apache.solr.common.params.CoreAdminParams.NAME;
 
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.ReloadCollectionRequestBody;
 import org.apache.solr.common.SolrException;
 import org.junit.Test;
 
@@ -34,7 +35,7 @@ public class ReloadCollectionAPITest extends SolrTestCaseJ4 {
             SolrException.class,
             () -> {
               final var api = new ReloadCollectionAPI(null, null, null);
-              api.reloadCollection(null, new ReloadCollectionAPI.ReloadCollectionRequestBody());
+              api.reloadCollection(null, new ReloadCollectionRequestBody());
             });
 
     assertEquals(400, thrown.code());
@@ -44,8 +45,8 @@ public class ReloadCollectionAPITest extends SolrTestCaseJ4 {
   // TODO message creation
   @Test
   public void testCreateRemoteMessageAllProperties() {
-    final var requestBody = new ReloadCollectionAPI.ReloadCollectionRequestBody();
-    requestBody.asyncId = "someAsyncId";
+    final var requestBody = new ReloadCollectionRequestBody();
+    requestBody.async = "someAsyncId";
     final var remoteMessage =
         ReloadCollectionAPI.createRemoteMessage("someCollName", requestBody).getProperties();
 
diff --git a/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java b/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java
index e26d4d2a73e..635dc8305e5 100644
--- a/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java
@@ -29,6 +29,7 @@ import java.util.List;
 import javax.inject.Singleton;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.Response;
+import org.apache.solr.client.api.model.ListConfigsetsResponse;
 import org.apache.solr.client.solrj.response.ConfigSetAdminResponse;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.ConfigSetService;
@@ -44,7 +45,7 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
- * Unit tests for {@link ListConfigSetsAPI}.
+ * Unit tests for {@link ListConfigSets}.
  *
  * <p>Serves primarily as a model and example of how to write unit tests using Jersey's test
  * framework.
@@ -63,7 +64,7 @@ public class ListConfigSetsAPITest extends JerseyTest {
     forceSet(TestProperties.CONTAINER_PORT, "0");
     resetMocks();
     final ResourceConfig config = new ResourceConfig();
-    config.register(ListConfigSetsAPI.class);
+    config.register(ListConfigSets.class);
     config.register(SolrJacksonMapper.class);
     config.register(
         new AbstractBinder() {
@@ -107,8 +108,7 @@ public class ListConfigSetsAPITest extends JerseyTest {
     when(mockCoreContainer.getConfigSetService()).thenReturn(configSetService);
     when(configSetService.listConfigs()).thenReturn(List.of("cs1", "cs2"));
 
-    final ListConfigSetsAPI.ListConfigsetsResponse response =
-        target("/cluster/configs").request().get(ListConfigSetsAPI.ListConfigsetsResponse.class);
+    final var response = target("/cluster/configs").request().get(ListConfigsetsResponse.class);
 
     assertNotNull(response.configSets);
     assertNull(response.error);
@@ -120,11 +120,11 @@ public class ListConfigSetsAPITest extends JerseyTest {
   /**
    * Test the v2 to v1 response mapping for /cluster/configs
    *
-   * <p>{@link org.apache.solr.handler.admin.ConfigSetsHandler} uses {@link ListConfigSetsAPI} (and
-   * its response class {@link ListConfigSetsAPI.ListConfigsetsResponse}) internally to serve the v1
-   * version of this functionality. So it's important to make sure that the v2 response stays
-   * compatible with SolrJ - both because that's important in its own right and because that ensures
-   * we haven't accidentally changed the v1 response format.
+   * <p>{@link org.apache.solr.handler.admin.ConfigSetsHandler} uses {@link ListConfigSets} (and its
+   * response class {@link ListConfigsetsResponse}) internally to serve the v1 version of this
+   * functionality. So it's important to make sure that the v2 response stays compatible with SolrJ
+   * - both because that's important in its own right and because that ensures we haven't
+   * accidentally changed the v1 response format.
    */
   @Test
   public void testListConfigsetsV1Compatibility() throws Exception {
@@ -132,8 +132,7 @@ public class ListConfigSetsAPITest extends JerseyTest {
     when(mockCoreContainer.getConfigSetService()).thenReturn(configSetService);
     when(configSetService.listConfigs()).thenReturn(List.of("cs1", "cs2"));
 
-    final ListConfigSetsAPI.ListConfigsetsResponse response =
-        target("/cluster/configs").request().get(ListConfigSetsAPI.ListConfigsetsResponse.class);
+    final var response = target("/cluster/configs").request().get(ListConfigsetsResponse.class);
     final NamedList<Object> squashedResponse = new NamedList<>();
     V2ApiUtils.squashIntoNamedList(squashedResponse, response);
     final ConfigSetAdminResponse.List solrjResponse = new ConfigSetAdminResponse.List();
diff --git a/solr/solrj/src/resources/java-template/api.mustache b/solr/solrj/src/resources/java-template/api.mustache
index bf53b49bdd5..84f7f06ebf3 100644
--- a/solr/solrj/src/resources/java-template/api.mustache
+++ b/solr/solrj/src/resources/java-template/api.mustache
@@ -98,7 +98,7 @@ public class {{classname}} {
              * @param {{paramName}} {{description}}
              */
             {{/description}}
-            public void {{schema.setter}}({{dataType}} {{paramName}}) {
+            public void {{schema.setter}}({{{dataType}}} {{paramName}}) {
                 this.{{paramName}} = {{paramName}};
             }
 
@@ -113,7 +113,7 @@ public class {{classname}} {
              * @param {{baseName}} {{description}}
              */
              {{/description}}
-             public void {{setter}}({{dataType}} {{baseName}}) {
+             public void {{setter}}({{{dataType}}} {{baseName}}) {
                this.requestBody.{{baseName}} = {{baseName}};
             }
             {{/vars}}