You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by kr...@apache.org on 2023/03/29 15:31:38 UTC

[solr] 02/03: SOLR-16427: Evaluate and fix errorprone rules - part 5 - MutablePublicArray

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

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

commit cf8dee1978652903ac0ba3258de6ac146f9329dc
Author: Kevin Risden <kr...@apache.org>
AuthorDate: Mon Feb 27 15:41:18 2023 -0500

    SOLR-16427: Evaluate and fix errorprone rules - part 5 - MutablePublicArray
---
 gradle/validation/error-prone.gradle               |    2 +-
 .../apache/solr/parser/QueryParserConstants.java   |    1 +
 .../src/java/org/apache/solr/schema/BoolField.java |    3 +
 .../src/java/org/apache/solr/util/ExportTool.java  |   68 +-
 .../src/java/org/apache/solr/util/PackageTool.java |   88 +-
 .../src/java/org/apache/solr/util/SolrCLI.java     | 1034 ++++++++++----------
 .../src/test/org/apache/solr/CursorPagingTest.java |    7 +-
 .../apache/solr/legacy/TestLegacyNumericUtils.java |   29 +-
 .../solr/legacy/TestNumericRangeQuery32.java       |    2 +-
 .../solr/legacy/TestNumericRangeQuery64.java       |    2 +-
 .../org/apache/solr/search/CursorMarkTest.java     |    2 +-
 .../spelling/ConjunctionSolrSpellCheckerTest.java  |   18 +-
 .../apache/solr/analytics/facet/SortableFacet.java |    1 -
 .../facet/LegacyAbstractAnalyticsFacetTest.java    |    2 +-
 .../apache/solr/common/util/JsonTextWriter.java    |    2 +
 .../java/org/apache/solr/common/util/StrUtils.java |    1 +
 solr/solrj/src/java/org/noggit/JSONUtil.java       |    9 +-
 17 files changed, 633 insertions(+), 638 deletions(-)

diff --git a/gradle/validation/error-prone.gradle b/gradle/validation/error-prone.gradle
index b742ebbc9f1..6dc46041477 100644
--- a/gradle/validation/error-prone.gradle
+++ b/gradle/validation/error-prone.gradle
@@ -398,7 +398,7 @@ allprojects { prj ->
             '-Xep:ModifySourceCollectionInStream:WARN',
             '-Xep:MultipleParallelOrSequentialCalls:WARN',
             '-Xep:MultipleUnaryOperatorsInMethodCall:WARN',
-            // '-Xep:MutablePublicArray:OFF', // todo check if useful or comment why not - this should be possible...
+            '-Xep:MutablePublicArray:WARN',
             '-Xep:NarrowCalculation:WARN',
             '-Xep:NarrowingCompoundAssignment:WARN',
             // '-Xep:NegativeCharLiteral:OFF', // todo check if useful or comment why not
diff --git a/solr/core/src/java/org/apache/solr/parser/QueryParserConstants.java b/solr/core/src/java/org/apache/solr/parser/QueryParserConstants.java
index 8b52abc9aeb..cab24e5aa94 100644
--- a/solr/core/src/java/org/apache/solr/parser/QueryParserConstants.java
+++ b/solr/core/src/java/org/apache/solr/parser/QueryParserConstants.java
@@ -89,6 +89,7 @@ public interface QueryParserConstants {
   int DEFAULT = 3;
 
   /** Literal token values. */
+  @SuppressWarnings("MutablePublicArray")
   String[] tokenImage = {
     "<EOF>",
     "<_NUM_CHAR>",
diff --git a/solr/core/src/java/org/apache/solr/schema/BoolField.java b/solr/core/src/java/org/apache/solr/schema/BoolField.java
index b198666cd43..5a9146ce08b 100644
--- a/solr/core/src/java/org/apache/solr/schema/BoolField.java
+++ b/solr/core/src/java/org/apache/solr/schema/BoolField.java
@@ -69,7 +69,10 @@ public class BoolField extends PrimitiveFieldType {
   }
 
   // avoid instantiating every time...
+  @SuppressWarnings("MutablePublicArray")
   public static final char[] TRUE_TOKEN = {'T'};
+
+  @SuppressWarnings("MutablePublicArray")
   public static final char[] FALSE_TOKEN = {'F'};
 
   ////////////////////////////////////////////////////////////////////////
diff --git a/solr/core/src/java/org/apache/solr/util/ExportTool.java b/solr/core/src/java/org/apache/solr/util/ExportTool.java
index 47137ab0258..50f78db8e77 100644
--- a/solr/core/src/java/org/apache/solr/util/ExportTool.java
+++ b/solr/core/src/java/org/apache/solr/util/ExportTool.java
@@ -90,7 +90,7 @@ public class ExportTool extends SolrCLI.ToolBase {
   }
 
   @Override
-  public Option[] getOptions() {
+  public List<Option> getOptions() {
     return OPTIONS;
   }
 
@@ -205,39 +205,39 @@ public class ExportTool extends SolrCLI.ToolBase {
     void end() throws IOException {}
   }
 
-  private static final Option[] OPTIONS = {
-    Option.builder("url")
-        .hasArg()
-        .required()
-        .desc("Address of the collection, example http://localhost:8983/solr/gettingstarted.")
-        .build(),
-    Option.builder("out")
-        .hasArg()
-        .required(false)
-        .desc("File name, defaults to 'collection-name.<format>'.")
-        .build(),
-    Option.builder("format")
-        .hasArg()
-        .required(false)
-        .desc(
-            "Output format for exported docs (json or javabin), defaulting to json. File extension would be .json.")
-        .build(),
-    Option.builder("limit")
-        .hasArg()
-        .required(false)
-        .desc("Maximum number of docs to download. Default is 100, use -1 for all docs.")
-        .build(),
-    Option.builder("query")
-        .hasArg()
-        .required(false)
-        .desc("A custom query, default is '*:*'.")
-        .build(),
-    Option.builder("fields")
-        .hasArg()
-        .required(false)
-        .desc("Comma separated list of fields to export. By default all fields are fetched.")
-        .build()
-  };
+  private static final List<Option> OPTIONS =
+      List.of(
+          Option.builder("url")
+              .hasArg()
+              .required()
+              .desc("Address of the collection, example http://localhost:8983/solr/gettingstarted.")
+              .build(),
+          Option.builder("out")
+              .hasArg()
+              .required(false)
+              .desc("File name, defaults to 'collection-name.<format>'.")
+              .build(),
+          Option.builder("format")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Output format for exported docs (json or javabin), defaulting to json. File extension would be .json.")
+              .build(),
+          Option.builder("limit")
+              .hasArg()
+              .required(false)
+              .desc("Maximum number of docs to download. Default is 100, use -1 for all docs.")
+              .build(),
+          Option.builder("query")
+              .hasArg()
+              .required(false)
+              .desc("A custom query, default is '*:*'.")
+              .build(),
+          Option.builder("fields")
+              .hasArg()
+              .required(false)
+              .desc("Comma separated list of fields to export. By default all fields are fetched.")
+              .build());
 
   static class JsonSink extends DocsSink {
     private CharArr charArr = new CharArr(1024 * 2);
diff --git a/solr/core/src/java/org/apache/solr/util/PackageTool.java b/solr/core/src/java/org/apache/solr/util/PackageTool.java
index 9605af748d3..e0e59b6bc88 100644
--- a/solr/core/src/java/org/apache/solr/util/PackageTool.java
+++ b/solr/core/src/java/org/apache/solr/util/PackageTool.java
@@ -22,6 +22,7 @@ import static org.apache.solr.packagemanager.PackageUtils.printGreen;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.List;
 import java.util.Map;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
@@ -314,49 +315,50 @@ public class PackageTool extends SolrCLI.ToolBase {
   }
 
   @Override
-  public Option[] getOptions() {
-    return new Option[] {
-      Option.builder("solrUrl")
-          .argName("URL")
-          .hasArg()
-          .required(true)
-          .desc(
-              "Address of the Solr Web application, defaults to: " + SolrCLI.DEFAULT_SOLR_URL + '.')
-          .build(),
-      Option.builder("collections")
-          .argName("COLLECTIONS")
-          .hasArg()
-          .required(false)
-          .desc(
-              "Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins.")
-          .build(),
-      Option.builder("cluster")
-          .required(false)
-          .desc("Specifies that this action should affect cluster-level plugins only.")
-          .build(),
-      Option.builder("p")
-          .argName("PARAMS")
-          .hasArgs()
-          .required(false)
-          .desc("List of parameters to be used with deploy command.")
-          .longOpt("param")
-          .build(),
-      Option.builder("u")
-          .required(false)
-          .desc("If a deployment is an update over a previous deployment.")
-          .longOpt("update")
-          .build(),
-      Option.builder("c")
-          .required(false)
-          .desc("The collection to apply the package to, not required.")
-          .longOpt("collection")
-          .build(),
-      Option.builder("y")
-          .required(false)
-          .desc("Don't prompt for input; accept all default choices, defaults to false.")
-          .longOpt("noprompt")
-          .build()
-    };
+  public List<Option> getOptions() {
+    return List.of(
+        Option.builder("solrUrl")
+            .argName("URL")
+            .hasArg()
+            .required(true)
+            .desc(
+                "Address of the Solr Web application, defaults to: "
+                    + SolrCLI.DEFAULT_SOLR_URL
+                    + '.')
+            .build(),
+        Option.builder("collections")
+            .argName("COLLECTIONS")
+            .hasArg()
+            .required(false)
+            .desc(
+                "Specifies that this action should affect plugins for the given collections only, excluding cluster level plugins.")
+            .build(),
+        Option.builder("cluster")
+            .required(false)
+            .desc("Specifies that this action should affect cluster-level plugins only.")
+            .build(),
+        Option.builder("p")
+            .argName("PARAMS")
+            .hasArgs()
+            .required(false)
+            .desc("List of parameters to be used with deploy command.")
+            .longOpt("param")
+            .build(),
+        Option.builder("u")
+            .required(false)
+            .desc("If a deployment is an update over a previous deployment.")
+            .longOpt("update")
+            .build(),
+        Option.builder("c")
+            .required(false)
+            .desc("The collection to apply the package to, not required.")
+            .longOpt("collection")
+            .build(),
+        Option.builder("y")
+            .required(false)
+            .desc("Don't prompt for input; accept all default choices, defaults to false.")
+            .longOpt("noprompt")
+            .build());
   }
 
   private String getZkHost(CommandLine cli) throws Exception {
diff --git a/solr/core/src/java/org/apache/solr/util/SolrCLI.java b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
index dd392e0a184..c8574c049bd 100755
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -57,6 +57,7 @@ import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import javax.net.ssl.SSLPeerUnverifiedException;
@@ -135,7 +136,7 @@ public class SolrCLI implements CLIO {
   public interface Tool {
     String getName();
 
-    Option[] getOptions();
+    List<Option> getOptions();
 
     int runTool(CommandLine cli) throws Exception;
   }
@@ -198,7 +199,7 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
+    public List<Option> getOptions() {
       return cloudOptions;
     }
 
@@ -255,18 +256,17 @@ public class SolrCLI implements CLIO {
           // .type(Boolean.class)
           .build();
 
-  public static final Option[] cloudOptions =
-      new Option[] {
-        OPTION_ZKHOST,
-        Option.builder("c")
-            .argName("COLLECTION")
-            .hasArg()
-            .required(false)
-            .desc("Name of collection; no default.")
-            .longOpt("collection")
-            .build(),
-        OPTION_VERBOSE
-      };
+  public static final List<Option> cloudOptions =
+      List.of(
+          OPTION_ZKHOST,
+          Option.builder("c")
+              .argName("COLLECTION")
+              .hasArg()
+              .required(false)
+              .desc("Name of collection; no default.")
+              .longOpt("collection")
+              .build(),
+          OPTION_VERBOSE);
 
   private static void exit(int exitStatus) {
     try {
@@ -315,11 +315,11 @@ public class SolrCLI implements CLIO {
    * @deprecated Use the method that takes a tool name as the first argument instead.
    */
   @Deprecated
-  public static CommandLine parseCmdLine(String[] args, Option[] toolOptions) throws Exception {
+  public static CommandLine parseCmdLine(String[] args, List<Option> toolOptions) throws Exception {
     return parseCmdLine(SolrCLI.class.getName(), args, toolOptions);
   }
 
-  public static CommandLine parseCmdLine(String toolName, String[] args, Option[] toolOptions)
+  public static CommandLine parseCmdLine(String toolName, String[] args, List<Option> toolOptions)
       throws Exception {
     // the parser doesn't like -D props
     List<String> toolArgList = new ArrayList<>();
@@ -381,8 +381,8 @@ public class SolrCLI implements CLIO {
   }
 
   /** Support options common to all tools. */
-  public static Option[] getCommonToolOptions() {
-    return new Option[0];
+  public static List<Option> getCommonToolOptions() {
+    return List.of();
   }
 
   // Creates an instance of the requested tool, using classpath scanning if necessary
@@ -450,49 +450,49 @@ public class SolrCLI implements CLIO {
     Options options = new Options();
     options.addOption("help", false, "Print this message");
     options.addOption(OPTION_VERBOSE);
-    Option[] toolOpts = joinCommonAndToolOptions(tool.getOptions());
-    for (int i = 0; i < toolOpts.length; i++) options.addOption(toolOpts[i]);
+    List<Option> toolOpts = joinCommonAndToolOptions(tool.getOptions());
+    for (Option toolOpt : toolOpts) {
+      options.addOption(toolOpt);
+    }
     return options;
   }
 
-  public static Option[] joinCommonAndToolOptions(Option[] toolOpts) {
+  public static List<Option> joinCommonAndToolOptions(List<Option> toolOpts) {
     return joinOptions(getCommonToolOptions(), toolOpts);
   }
 
-  public static Option[] joinOptions(Option[] lhs, Option[] rhs) {
+  public static List<Option> joinOptions(List<Option> lhs, List<Option> rhs) {
     if (lhs == null) {
-      return rhs == null ? new Option[0] : rhs;
+      return rhs == null ? List.of() : rhs;
     }
 
     if (rhs == null) {
       return lhs;
     }
 
-    Option[] options = new Option[lhs.length + rhs.length];
-    System.arraycopy(lhs, 0, options, 0, lhs.length);
-    System.arraycopy(rhs, 0, options, lhs.length, rhs.length);
-
-    return options;
+    return Stream.concat(lhs.stream(), rhs.stream()).collect(Collectors.toUnmodifiableList());
   }
 
   /**
    * @deprecated Use the method that takes a tool name as the first argument instead.
    */
   @Deprecated
-  public static CommandLine processCommandLineArgs(Option[] customOptions, String[] args) {
+  public static CommandLine processCommandLineArgs(List<Option> customOptions, String[] args) {
     return processCommandLineArgs(SolrCLI.class.getName(), customOptions, args);
   }
 
   /** Parses the command-line arguments passed by the user. */
   public static CommandLine processCommandLineArgs(
-      String toolName, Option[] customOptions, String[] args) {
+      String toolName, List<Option> customOptions, String[] args) {
     Options options = new Options();
 
     options.addOption("help", false, "Print this message");
     options.addOption(OPTION_VERBOSE);
 
     if (customOptions != null) {
-      for (int i = 0; i < customOptions.length; i++) options.addOption(customOptions[i]);
+      for (Option customOption : customOptions) {
+        options.addOption(customOption);
+      }
     }
 
     CommandLine cli = null;
@@ -500,9 +500,9 @@ public class SolrCLI implements CLIO {
       cli = (new GnuParser()).parse(options, args);
     } catch (ParseException exp) {
       boolean hasHelpArg = false;
-      if (args != null && args.length > 0) {
-        for (int z = 0; z < args.length; z++) {
-          if ("--help".equals(args[z]) || "-help".equals(args[z])) {
+      if (args != null) {
+        for (String arg : args) {
+          if ("--help".equals(arg) || "-help".equals(arg)) {
             hasHelpArg = true;
             break;
           }
@@ -887,21 +887,20 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("solr")
-            .argName("URL")
-            .hasArg()
-            .required(false)
-            .desc("Address of the Solr Web application, defaults to: " + DEFAULT_SOLR_URL + '.')
-            .build(),
-        Option.builder("maxWaitSecs")
-            .argName("SECS")
-            .hasArg()
-            .required(false)
-            .desc("Wait up to the specified number of seconds to see Solr running.")
-            .build()
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("solr")
+              .argName("URL")
+              .hasArg()
+              .required(false)
+              .desc("Address of the Solr Web application, defaults to: " + DEFAULT_SOLR_URL + '.')
+              .build(),
+          Option.builder("maxWaitSecs")
+              .argName("SECS")
+              .hasArg()
+              .required(false)
+              .desc("Wait up to the specified number of seconds to see Solr running.")
+              .build());
     }
 
     @Override
@@ -1042,15 +1041,14 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("get")
-            .argName("URL")
-            .hasArg()
-            .required(true)
-            .desc("Send a GET request to a Solr API endpoint.")
-            .build()
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("get")
+              .argName("URL")
+              .hasArg()
+              .required(true)
+              .desc("Send a GET request to a Solr API endpoint.")
+              .build());
     }
 
     @Override
@@ -1377,52 +1375,51 @@ public class SolrCLI implements CLIO {
     }
   } // end HealthcheckTool
 
-  private static final Option[] CREATE_COLLECTION_OPTIONS =
-      new Option[] {
-        OPTION_ZKHOST,
-        OPTION_SOLRURL,
-        Option.builder(NAME)
-            .argName("NAME")
-            .hasArg()
-            .required(true)
-            .desc("Name of collection to create.")
-            .build(),
-        Option.builder("shards")
-            .argName("#")
-            .hasArg()
-            .required(false)
-            .desc("Number of shards; default is 1.")
-            .build(),
-        Option.builder("replicationFactor")
-            .argName("#")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Number of copies of each document across the collection (replicas per shard); default is 1.")
-            .build(),
-        Option.builder("confdir")
-            .argName("NAME")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Configuration directory to copy when creating the new collection; default is "
-                    + DEFAULT_CONFIG_SET
-                    + '.')
-            .build(),
-        Option.builder("confname")
-            .argName("NAME")
-            .hasArg()
-            .required(false)
-            .desc("Configuration name; default is the collection name.")
-            .build(),
-        Option.builder("configsetsDir")
-            .argName("DIR")
-            .hasArg()
-            .required(true)
-            .desc("Path to configsets directory on the local system.")
-            .build(),
-        OPTION_VERBOSE
-      };
+  private static final List<Option> CREATE_COLLECTION_OPTIONS =
+      List.of(
+          OPTION_ZKHOST,
+          OPTION_SOLRURL,
+          Option.builder(NAME)
+              .argName("NAME")
+              .hasArg()
+              .required(true)
+              .desc("Name of collection to create.")
+              .build(),
+          Option.builder("shards")
+              .argName("#")
+              .hasArg()
+              .required(false)
+              .desc("Number of shards; default is 1.")
+              .build(),
+          Option.builder("replicationFactor")
+              .argName("#")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Number of copies of each document across the collection (replicas per shard); default is 1.")
+              .build(),
+          Option.builder("confdir")
+              .argName("NAME")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Configuration directory to copy when creating the new collection; default is "
+                      + DEFAULT_CONFIG_SET
+                      + '.')
+              .build(),
+          Option.builder("confname")
+              .argName("NAME")
+              .hasArg()
+              .required(false)
+              .desc("Configuration name; default is the collection name.")
+              .build(),
+          Option.builder("configsetsDir")
+              .argName("DIR")
+              .hasArg()
+              .required(true)
+              .desc("Path to configsets directory on the local system.")
+              .build(),
+          OPTION_VERBOSE);
 
   /**
    * Get the base URL of a live Solr instance from either the solrUrl command-line option from
@@ -1552,7 +1549,7 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
+    public List<Option> getOptions() {
       return CREATE_COLLECTION_OPTIONS;
     }
 
@@ -1714,32 +1711,31 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        OPTION_SOLRURL,
-        Option.builder(NAME)
-            .argName("NAME")
-            .hasArg()
-            .required(true)
-            .desc("Name of the core to create.")
-            .build(),
-        Option.builder("confdir")
-            .argName("CONFIG")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Configuration directory to copy when creating the new core; default is "
-                    + DEFAULT_CONFIG_SET
-                    + '.')
-            .build(),
-        Option.builder("configsetsDir")
-            .argName("DIR")
-            .hasArg()
-            .required(true)
-            .desc("Path to configsets directory on the local system.")
-            .build(),
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          OPTION_SOLRURL,
+          Option.builder(NAME)
+              .argName("NAME")
+              .hasArg()
+              .required(true)
+              .desc("Name of the core to create.")
+              .build(),
+          Option.builder("confdir")
+              .argName("CONFIG")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Configuration directory to copy when creating the new core; default is "
+                      + DEFAULT_CONFIG_SET
+                      + '.')
+              .build(),
+          Option.builder("configsetsDir")
+              .argName("DIR")
+              .hasArg()
+              .required(true)
+              .desc("Path to configsets directory on the local system.")
+              .build(),
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -1876,7 +1872,7 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
+    public List<Option> getOptions() {
       return CREATE_COLLECTION_OPTIONS;
     }
 
@@ -1915,29 +1911,28 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("confname")
-            .argName("confname") // Comes out in help message
-            .hasArg() // Has one sub-argument
-            .required(true) // confname argument must be present
-            .desc("Configset name in ZooKeeper.")
-            .build(), // passed as -confname value
-        Option.builder("confdir")
-            .argName("confdir")
-            .hasArg()
-            .required(true)
-            .desc("Local directory with configs.")
-            .build(),
-        Option.builder("configsetsDir")
-            .argName("configsetsDir")
-            .hasArg()
-            .required(false)
-            .desc("Parent directory of example configsets.")
-            .build(),
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("confname")
+              .argName("confname") // Comes out in help message
+              .hasArg() // Has one sub-argument
+              .required(true) // confname argument must be present
+              .desc("Configset name in ZooKeeper.")
+              .build(), // passed as -confname value
+          Option.builder("confdir")
+              .argName("confdir")
+              .hasArg()
+              .required(true)
+              .desc("Local directory with configs.")
+              .build(),
+          Option.builder("configsetsDir")
+              .argName("configsetsDir")
+              .hasArg()
+              .required(false)
+              .desc("Parent directory of example configsets.")
+              .build(),
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -1998,23 +1993,22 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("confname")
-            .argName("confname")
-            .hasArg()
-            .required(true)
-            .desc("Configset name in ZooKeeper.")
-            .build(),
-        Option.builder("confdir")
-            .argName("confdir")
-            .hasArg()
-            .required(true)
-            .desc("Local directory with configs.")
-            .build(),
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("confname")
+              .argName("confname")
+              .hasArg()
+              .required(true)
+              .desc("Configset name in ZooKeeper.")
+              .build(),
+          Option.builder("confdir")
+              .argName("confdir")
+              .hasArg()
+              .required(true)
+              .desc("Local directory with configs.")
+              .build(),
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2075,18 +2069,17 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("path")
-            .argName("path")
-            .hasArg()
-            .required(true)
-            .desc("Path to remove.")
-            .build(),
-        OPTION_RECURSE,
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("path")
+              .argName("path")
+              .hasArg()
+              .required(true)
+              .desc("Path to remove.")
+              .build(),
+          OPTION_RECURSE,
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2151,18 +2144,17 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("path")
-            .argName("path")
-            .hasArg()
-            .required(true)
-            .desc("Path to list.")
-            .build(),
-        OPTION_RECURSE,
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("path")
+              .argName("path")
+              .hasArg()
+              .required(true)
+              .desc("Path to list.")
+              .build(),
+          OPTION_RECURSE,
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2218,17 +2210,16 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("path")
-            .argName("path")
-            .hasArg()
-            .required(true)
-            .desc("Path to create.")
-            .build(),
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("path")
+              .argName("path")
+              .hasArg()
+              .required(true)
+              .desc("Path to create.")
+              .build(),
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2276,24 +2267,23 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("src")
-            .argName("src")
-            .hasArg()
-            .required(true)
-            .desc("Source file or directory, may be local or a Znode.")
-            .build(),
-        Option.builder("dst")
-            .argName("dst")
-            .hasArg()
-            .required(true)
-            .desc("Destination of copy, may be local or a Znode.")
-            .build(),
-        OPTION_RECURSE,
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("src")
+              .argName("src")
+              .hasArg()
+              .required(true)
+              .desc("Source file or directory, may be local or a Znode.")
+              .build(),
+          Option.builder("dst")
+              .argName("dst")
+              .hasArg()
+              .required(true)
+              .desc("Destination of copy, may be local or a Znode.")
+              .build(),
+          OPTION_RECURSE,
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2360,23 +2350,22 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("src")
-            .argName("src")
-            .hasArg()
-            .required(true)
-            .desc("Source Znode to move from.")
-            .build(),
-        Option.builder("dst")
-            .argName("dst")
-            .hasArg()
-            .required(true)
-            .desc("Destination Znode to move to.")
-            .build(),
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("src")
+              .argName("src")
+              .hasArg()
+              .required(true)
+              .desc("Source Znode to move from.")
+              .build(),
+          Option.builder("dst")
+              .argName("dst")
+              .hasArg()
+              .required(true)
+              .desc("Destination Znode to move to.")
+              .build(),
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2444,30 +2433,29 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        OPTION_SOLRURL,
-        Option.builder(NAME)
-            .argName("NAME")
-            .hasArg()
-            .required(true)
-            .desc("Name of the core / collection to delete.")
-            .build(),
-        Option.builder("deleteConfig")
-            .argName("true|false")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Flag to indicate if the underlying configuration directory for a collection should also be deleted; default is true.")
-            .build(),
-        Option.builder("forceDeleteConfig")
-            .required(false)
-            .desc(
-                "Skip safety checks when deleting the configuration directory used by a collection.")
-            .build(),
-        OPTION_ZKHOST,
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          OPTION_SOLRURL,
+          Option.builder(NAME)
+              .argName("NAME")
+              .hasArg()
+              .required(true)
+              .desc("Name of the core / collection to delete.")
+              .build(),
+          Option.builder("deleteConfig")
+              .argName("true|false")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Flag to indicate if the underlying configuration directory for a collection should also be deleted; default is true.")
+              .build(),
+          Option.builder("forceDeleteConfig")
+              .required(false)
+              .desc(
+                  "Skip safety checks when deleting the configuration directory used by a collection.")
+              .build(),
+          OPTION_ZKHOST,
+          OPTION_VERBOSE);
     }
 
     @Override
@@ -2648,47 +2636,46 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      Option[] configOptions =
-          new Option[] {
-            Option.builder("action")
-                .argName("ACTION")
-                .hasArg()
-                .required(false)
-                .desc(
-                    "Config API action, one of: set-property, unset-property; default is 'set-property'.")
-                .build(),
-            Option.builder("property")
-                .argName("PROP")
-                .hasArg()
-                .required(true)
-                .desc(
-                    "Name of the Config API property to apply the action to, such as: 'updateHandler.autoSoftCommit.maxTime'.")
-                .build(),
-            Option.builder("value")
-                .argName("VALUE")
-                .hasArg()
-                .required(false)
-                .desc("Set the property to this value; accepts JSON objects and strings.")
-                .build(),
-            OPTION_SOLRURL,
-            OPTION_ZKHOST,
-            Option.builder("p")
-                .argName("PORT")
-                .hasArg()
-                .required(false)
-                .desc("The port of the Solr node to use when applying configuration change.")
-                .longOpt("port")
-                .build(),
-            Option.builder("s")
-                .argName("SCHEME")
-                .hasArg()
-                .required(false)
-                .desc(
-                    "The scheme for accessing Solr.  Accepted values: http or https.  Default is 'http'")
-                .longOpt("scheme")
-                .build()
-          };
+    public List<Option> getOptions() {
+      List<Option> configOptions =
+          List.of(
+              Option.builder("action")
+                  .argName("ACTION")
+                  .hasArg()
+                  .required(false)
+                  .desc(
+                      "Config API action, one of: set-property, unset-property; default is 'set-property'.")
+                  .build(),
+              Option.builder("property")
+                  .argName("PROP")
+                  .hasArg()
+                  .required(true)
+                  .desc(
+                      "Name of the Config API property to apply the action to, such as: 'updateHandler.autoSoftCommit.maxTime'.")
+                  .build(),
+              Option.builder("value")
+                  .argName("VALUE")
+                  .hasArg()
+                  .required(false)
+                  .desc("Set the property to this value; accepts JSON objects and strings.")
+                  .build(),
+              OPTION_SOLRURL,
+              OPTION_ZKHOST,
+              Option.builder("p")
+                  .argName("PORT")
+                  .hasArg()
+                  .required(false)
+                  .desc("The port of the Solr node to use when applying configuration change.")
+                  .longOpt("port")
+                  .build(),
+              Option.builder("s")
+                  .argName("SCHEME")
+                  .hasArg()
+                  .required(false)
+                  .desc(
+                      "The scheme for accessing Solr.  Accepted values: http or https.  Default is 'http'")
+                  .longOpt("scheme")
+                  .build());
       return joinOptions(configOptions, cloudOptions);
     }
 
@@ -2781,94 +2768,95 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("noprompt")
-            .required(false)
-            .desc(
-                "Don't prompt for input; accept all defaults when running examples that accept user input.")
-            .build(),
-        Option.builder("e")
-            .argName("NAME")
-            .hasArg()
-            .required(true)
-            .desc("Name of the example to launch, one of: cloud, techproducts, schemaless, films.")
-            .longOpt("example")
-            .build(),
-        Option.builder("script")
-            .argName("PATH")
-            .hasArg()
-            .required(false)
-            .desc("Path to the bin/solr script.")
-            .build(),
-        Option.builder("d")
-            .argName("DIR")
-            .hasArg()
-            .required(true)
-            .desc("Path to the Solr server directory.")
-            .longOpt("serverDir")
-            .build(),
-        Option.builder("force")
-            .argName("FORCE")
-            .desc("Force option in case Solr is run as root.")
-            .build(),
-        Option.builder("exampleDir")
-            .argName("DIR")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Path to the Solr example directory; if not provided, ${serverDir}/../example is expected to exist.")
-            .build(),
-        Option.builder("urlScheme")
-            .argName("SCHEME")
-            .hasArg()
-            .required(false)
-            .desc("Solr URL scheme: http or https, defaults to http if not specified.")
-            .build(),
-        Option.builder("p")
-            .argName("PORT")
-            .hasArg()
-            .required(false)
-            .desc("Specify the port to start the Solr HTTP listener on; default is 8983.")
-            .longOpt("port")
-            .build(),
-        Option.builder("h")
-            .argName("HOSTNAME")
-            .hasArg()
-            .required(false)
-            .desc("Specify the hostname for this Solr instance.")
-            .longOpt("host")
-            .build(),
-        Option.builder("z")
-            .argName("ZKHOST")
-            .hasArg()
-            .required(false)
-            .desc("ZooKeeper connection string; only used when running in SolrCloud mode using -c.")
-            .longOpt("zkhost")
-            .build(),
-        Option.builder("c")
-            .required(false)
-            .desc(
-                "Start Solr in SolrCloud mode; if -z not supplied, an embedded ZooKeeper instance is started on Solr port+1000, such as 9983 if Solr is bound to 8983.")
-            .longOpt("cloud")
-            .build(),
-        Option.builder("m")
-            .argName("MEM")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Sets the min (-Xms) and max (-Xmx) heap size for the JVM, such as: -m 4g results in: -Xms4g -Xmx4g; by default, this script sets the heap size to 512m.")
-            .longOpt("memory")
-            .build(),
-        Option.builder("a")
-            .argName("OPTS")
-            .hasArg()
-            .required(false)
-            .desc(
-                "Additional options to be passed to the JVM when starting example Solr server(s).")
-            .longOpt("addlopts")
-            .build()
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("noprompt")
+              .required(false)
+              .desc(
+                  "Don't prompt for input; accept all defaults when running examples that accept user input.")
+              .build(),
+          Option.builder("e")
+              .argName("NAME")
+              .hasArg()
+              .required(true)
+              .desc(
+                  "Name of the example to launch, one of: cloud, techproducts, schemaless, films.")
+              .longOpt("example")
+              .build(),
+          Option.builder("script")
+              .argName("PATH")
+              .hasArg()
+              .required(false)
+              .desc("Path to the bin/solr script.")
+              .build(),
+          Option.builder("d")
+              .argName("DIR")
+              .hasArg()
+              .required(true)
+              .desc("Path to the Solr server directory.")
+              .longOpt("serverDir")
+              .build(),
+          Option.builder("force")
+              .argName("FORCE")
+              .desc("Force option in case Solr is run as root.")
+              .build(),
+          Option.builder("exampleDir")
+              .argName("DIR")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Path to the Solr example directory; if not provided, ${serverDir}/../example is expected to exist.")
+              .build(),
+          Option.builder("urlScheme")
+              .argName("SCHEME")
+              .hasArg()
+              .required(false)
+              .desc("Solr URL scheme: http or https, defaults to http if not specified.")
+              .build(),
+          Option.builder("p")
+              .argName("PORT")
+              .hasArg()
+              .required(false)
+              .desc("Specify the port to start the Solr HTTP listener on; default is 8983.")
+              .longOpt("port")
+              .build(),
+          Option.builder("h")
+              .argName("HOSTNAME")
+              .hasArg()
+              .required(false)
+              .desc("Specify the hostname for this Solr instance.")
+              .longOpt("host")
+              .build(),
+          Option.builder("z")
+              .argName("ZKHOST")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "ZooKeeper connection string; only used when running in SolrCloud mode using -c.")
+              .longOpt("zkhost")
+              .build(),
+          Option.builder("c")
+              .required(false)
+              .desc(
+                  "Start Solr in SolrCloud mode; if -z not supplied, an embedded ZooKeeper instance is started on Solr port+1000, such as 9983 if Solr is bound to 8983.")
+              .longOpt("cloud")
+              .build(),
+          Option.builder("m")
+              .argName("MEM")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Sets the min (-Xms) and max (-Xmx) heap size for the JVM, such as: -m 4g results in: -Xms4g -Xmx4g; by default, this script sets the heap size to 512m.")
+              .longOpt("memory")
+              .build(),
+          Option.builder("a")
+              .argName("OPTS")
+              .hasArg()
+              .required(false)
+              .desc(
+                  "Additional options to be passed to the JVM when starting example Solr server(s).")
+              .longOpt("addlopts")
+              .build());
     }
 
     @Override
@@ -3787,75 +3775,74 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("R")
-            .desc("Asserts that we are NOT the root user.")
-            .longOpt("not-root")
-            .build(),
-        Option.builder("r").desc("Asserts that we are the root user.").longOpt("root").build(),
-        Option.builder("S")
-            .desc("Asserts that Solr is NOT running on a certain URL. Default timeout is 1000ms.")
-            .longOpt("not-started")
-            .hasArg(true)
-            .argName("url")
-            .build(),
-        Option.builder("s")
-            .desc("Asserts that Solr is running on a certain URL. Default timeout is 1000ms.")
-            .longOpt("started")
-            .hasArg(true)
-            .argName("url")
-            .build(),
-        Option.builder("u")
-            .desc("Asserts that we run as same user that owns <directory>.")
-            .longOpt("same-user")
-            .hasArg(true)
-            .argName("directory")
-            .build(),
-        Option.builder("x")
-            .desc("Asserts that directory <directory> exists.")
-            .longOpt("exists")
-            .hasArg(true)
-            .argName("directory")
-            .build(),
-        Option.builder("X")
-            .desc("Asserts that directory <directory> does NOT exist.")
-            .longOpt("not-exists")
-            .hasArg(true)
-            .argName("directory")
-            .build(),
-        Option.builder("c")
-            .desc(
-                "Asserts that Solr is running in cloud mode.  Also fails if Solr not running.  URL should be for root Solr path.")
-            .longOpt("cloud")
-            .hasArg(true)
-            .argName("url")
-            .build(),
-        Option.builder("C")
-            .desc(
-                "Asserts that Solr is not running in cloud mode.  Also fails if Solr not running.  URL should be for root Solr path.")
-            .longOpt("not-cloud")
-            .hasArg(true)
-            .argName("url")
-            .build(),
-        Option.builder("m")
-            .desc("Exception message to be used in place of the default error message.")
-            .longOpt("message")
-            .hasArg(true)
-            .argName("message")
-            .build(),
-        Option.builder("t")
-            .desc("Timeout in ms for commands supporting a timeout.")
-            .longOpt("timeout")
-            .hasArg(true)
-            .type(Long.class)
-            .argName("ms")
-            .build(),
-        Option.builder("e")
-            .desc("Return an exit code instead of printing error message on assert fail.")
-            .longOpt("exitcode")
-            .build()
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("R")
+              .desc("Asserts that we are NOT the root user.")
+              .longOpt("not-root")
+              .build(),
+          Option.builder("r").desc("Asserts that we are the root user.").longOpt("root").build(),
+          Option.builder("S")
+              .desc("Asserts that Solr is NOT running on a certain URL. Default timeout is 1000ms.")
+              .longOpt("not-started")
+              .hasArg(true)
+              .argName("url")
+              .build(),
+          Option.builder("s")
+              .desc("Asserts that Solr is running on a certain URL. Default timeout is 1000ms.")
+              .longOpt("started")
+              .hasArg(true)
+              .argName("url")
+              .build(),
+          Option.builder("u")
+              .desc("Asserts that we run as same user that owns <directory>.")
+              .longOpt("same-user")
+              .hasArg(true)
+              .argName("directory")
+              .build(),
+          Option.builder("x")
+              .desc("Asserts that directory <directory> exists.")
+              .longOpt("exists")
+              .hasArg(true)
+              .argName("directory")
+              .build(),
+          Option.builder("X")
+              .desc("Asserts that directory <directory> does NOT exist.")
+              .longOpt("not-exists")
+              .hasArg(true)
+              .argName("directory")
+              .build(),
+          Option.builder("c")
+              .desc(
+                  "Asserts that Solr is running in cloud mode.  Also fails if Solr not running.  URL should be for root Solr path.")
+              .longOpt("cloud")
+              .hasArg(true)
+              .argName("url")
+              .build(),
+          Option.builder("C")
+              .desc(
+                  "Asserts that Solr is not running in cloud mode.  Also fails if Solr not running.  URL should be for root Solr path.")
+              .longOpt("not-cloud")
+              .hasArg(true)
+              .argName("url")
+              .build(),
+          Option.builder("m")
+              .desc("Exception message to be used in place of the default error message.")
+              .longOpt("message")
+              .hasArg(true)
+              .argName("message")
+              .build(),
+          Option.builder("t")
+              .desc("Timeout in ms for commands supporting a timeout.")
+              .longOpt("timeout")
+              .hasArg(true)
+              .type(Long.class)
+              .argName("ms")
+              .build(),
+          Option.builder("e")
+              .desc("Return an exit code instead of printing error message on assert fail.")
+              .longOpt("exitcode")
+              .build());
     }
 
     @Override
@@ -4130,66 +4117,65 @@ public class SolrCLI implements CLIO {
             "SOLR_AUTHENTICATION_CLIENT_BUILDER", "SOLR_AUTH_TYPE", "SOLR_AUTHENTICATION_OPTS");
 
     @Override
-    public Option[] getOptions() {
-      return new Option[] {
-        Option.builder("type")
-            .argName("type")
-            .hasArg()
-            .desc(
-                "The authentication mechanism to enable (basicAuth or kerberos). Defaults to 'basicAuth'.")
-            .build(),
-        Option.builder("credentials")
-            .argName("credentials")
-            .hasArg()
-            .desc(
-                "Credentials in the format username:password. Example: -credentials solr:SolrRocks")
-            .build(),
-        Option.builder("prompt")
-            .argName("prompt")
-            .hasArg()
-            .desc(
-                "Prompts the user to provide the credentials. Use either -credentials or -prompt, not both.")
-            .build(),
-        Option.builder("config")
-            .argName("config")
-            .hasArgs()
-            .desc(
-                "Configuration parameters (Solr startup parameters). Required for Kerberos authentication.")
-            .build(),
-        Option.builder("blockUnknown")
-            .argName("blockUnknown")
-            .desc(
-                "Blocks all access for unknown users (requires authentication for all endpoints).")
-            .hasArg()
-            .build(),
-        Option.builder("solrIncludeFile")
-            .argName("solrIncludeFile")
-            .hasArg()
-            .desc(
-                "The Solr include file which contains overridable environment variables for configuring Solr configurations.")
-            .build(),
-        Option.builder("updateIncludeFileOnly")
-            .argName("updateIncludeFileOnly")
-            .desc(
-                "Only update the solr.in.sh or solr.in.cmd file, and skip actual enabling/disabling"
-                    + " authentication (i.e. don't update security.json).")
-            .hasArg()
-            .build(),
-        Option.builder("authConfDir")
-            .argName("authConfDir")
-            .hasArg()
-            .required()
-            .desc(
-                "This is where any authentication related configuration files, if any, would be placed.")
-            .build(),
-        Option.builder("solrUrl").argName("solrUrl").hasArg().desc("Solr URL.").build(),
-        Option.builder("zkHost")
-            .argName("zkHost")
-            .hasArg()
-            .desc("ZooKeeper host to connect to.")
-            .build(),
-        OPTION_VERBOSE
-      };
+    public List<Option> getOptions() {
+      return List.of(
+          Option.builder("type")
+              .argName("type")
+              .hasArg()
+              .desc(
+                  "The authentication mechanism to enable (basicAuth or kerberos). Defaults to 'basicAuth'.")
+              .build(),
+          Option.builder("credentials")
+              .argName("credentials")
+              .hasArg()
+              .desc(
+                  "Credentials in the format username:password. Example: -credentials solr:SolrRocks")
+              .build(),
+          Option.builder("prompt")
+              .argName("prompt")
+              .hasArg()
+              .desc(
+                  "Prompts the user to provide the credentials. Use either -credentials or -prompt, not both.")
+              .build(),
+          Option.builder("config")
+              .argName("config")
+              .hasArgs()
+              .desc(
+                  "Configuration parameters (Solr startup parameters). Required for Kerberos authentication.")
+              .build(),
+          Option.builder("blockUnknown")
+              .argName("blockUnknown")
+              .desc(
+                  "Blocks all access for unknown users (requires authentication for all endpoints).")
+              .hasArg()
+              .build(),
+          Option.builder("solrIncludeFile")
+              .argName("solrIncludeFile")
+              .hasArg()
+              .desc(
+                  "The Solr include file which contains overridable environment variables for configuring Solr configurations.")
+              .build(),
+          Option.builder("updateIncludeFileOnly")
+              .argName("updateIncludeFileOnly")
+              .desc(
+                  "Only update the solr.in.sh or solr.in.cmd file, and skip actual enabling/disabling"
+                      + " authentication (i.e. don't update security.json).")
+              .hasArg()
+              .build(),
+          Option.builder("authConfDir")
+              .argName("authConfDir")
+              .hasArg()
+              .required()
+              .desc(
+                  "This is where any authentication related configuration files, if any, would be placed.")
+              .build(),
+          Option.builder("solrUrl").argName("solrUrl").hasArg().desc("Solr URL.").build(),
+          Option.builder("zkHost")
+              .argName("zkHost")
+              .hasArg()
+              .desc("ZooKeeper host to connect to.")
+              .build(),
+          OPTION_VERBOSE);
     }
 
     private void ensureArgumentIsValidBooleanIfPresent(CommandLine cli, String argName) {
diff --git a/solr/core/src/test/org/apache/solr/CursorPagingTest.java b/solr/core/src/test/org/apache/solr/CursorPagingTest.java
index 7e5e9131f06..2cda1deb407 100644
--- a/solr/core/src/test/org/apache/solr/CursorPagingTest.java
+++ b/solr/core/src/test/org/apache/solr/CursorPagingTest.java
@@ -62,9 +62,8 @@ public class CursorPagingTest extends SolrTestCaseJ4 {
   /** schema.xml file name, shared with other cursor related tests */
   public static final String TEST_SCHEMAXML_NAME = "schema-sorts.xml";
   /** values from enumConfig.xml */
-  public static final String[] SEVERITY_ENUM_VALUES = {
-    "Not Available", "Low", "Medium", "High", "Critical"
-  };
+  public static final List<String> SEVERITY_ENUM_VALUES =
+      List.of("Not Available", "Low", "Medium", "High", "Critical");
 
   @BeforeClass
   public static void beforeTests() throws Exception {
@@ -1273,7 +1272,7 @@ public class CursorPagingTest extends SolrTestCaseJ4 {
   }
 
   private static String randomEnumValue() {
-    return SEVERITY_ENUM_VALUES[random().nextInt(SEVERITY_ENUM_VALUES.length)];
+    return SEVERITY_ENUM_VALUES.get(random().nextInt(SEVERITY_ENUM_VALUES.size()));
   }
 
   /**
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java b/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
index ede3b8f2b8f..5a4ff489d12 100644
--- a/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
+++ b/solr/core/src/test/org/apache/solr/legacy/TestLegacyNumericUtils.java
@@ -19,6 +19,7 @@ package org.apache.solr.legacy;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Random;
 import org.apache.lucene.util.BytesRefBuilder;
 import org.apache.lucene.util.FixedBitSet;
@@ -236,13 +237,13 @@ public class TestLegacyNumericUtils extends SolrTestCase {
     }
   }
 
-  public static final double[] DOUBLE_NANs = {
-    Double.NaN,
-    Double.longBitsToDouble(0x7ff0000000000001L),
-    Double.longBitsToDouble(0x7fffffffffffffffL),
-    Double.longBitsToDouble(0xfff0000000000001L),
-    Double.longBitsToDouble(0xffffffffffffffffL)
-  };
+  public static final List<Double> DOUBLE_NANs =
+      List.of(
+          Double.NaN,
+          Double.longBitsToDouble(0x7ff0000000000001L),
+          Double.longBitsToDouble(0x7fffffffffffffffL),
+          Double.longBitsToDouble(0xfff0000000000001L),
+          Double.longBitsToDouble(0xffffffffffffffffL));
 
   public void testSortableDoubleNaN() {
     final long plusInf = NumericUtils.doubleToSortableLong(Double.POSITIVE_INFINITY);
@@ -296,13 +297,13 @@ public class TestLegacyNumericUtils extends SolrTestCase {
     }
   }
 
-  public static final float[] FLOAT_NANs = {
-    Float.NaN,
-    Float.intBitsToFloat(0x7f800001),
-    Float.intBitsToFloat(0x7fffffff),
-    Float.intBitsToFloat(0xff800001),
-    Float.intBitsToFloat(0xffffffff)
-  };
+  public static final List<Float> FLOAT_NANs =
+      List.of(
+          Float.NaN,
+          Float.intBitsToFloat(0x7f800001),
+          Float.intBitsToFloat(0x7fffffff),
+          Float.intBitsToFloat(0xff800001),
+          Float.intBitsToFloat(0xffffffff));
 
   public void testSortableFloatNaN() {
     final int plusInf = NumericUtils.floatToSortableInt(Float.POSITIVE_INFINITY);
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
index 73481b5f0b5..cd2e480a49a 100644
--- a/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
+++ b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery32.java
@@ -396,7 +396,7 @@ public class TestNumericRangeQuery32 extends SolrTestCase {
     q = LegacyNumericRangeQuery.newFloatRange("float", Float.NaN, Float.NaN, true, true);
     topDocs = s.search(q, 10);
     assertEquals(
-        "Score doc count", TestLegacyNumericUtils.FLOAT_NANs.length, topDocs.scoreDocs.length);
+        "Score doc count", TestLegacyNumericUtils.FLOAT_NANs.size(), topDocs.scoreDocs.length);
 
     r.close();
     dir.close();
diff --git a/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery64.java b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery64.java
index 4cc2adfb73e..97bac5ef1b5 100644
--- a/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery64.java
+++ b/solr/core/src/test/org/apache/solr/legacy/TestNumericRangeQuery64.java
@@ -419,7 +419,7 @@ public class TestNumericRangeQuery64 extends SolrTestCase {
     q = LegacyNumericRangeQuery.newDoubleRange("double", Double.NaN, Double.NaN, true, true);
     topDocs = s.search(q, 10);
     assertEquals(
-        "Score doc count", TestLegacyNumericUtils.DOUBLE_NANs.length, topDocs.scoreDocs.length);
+        "Score doc count", TestLegacyNumericUtils.DOUBLE_NANs.size(), topDocs.scoreDocs.length);
 
     r.close();
     dir.close();
diff --git a/solr/core/src/test/org/apache/solr/search/CursorMarkTest.java b/solr/core/src/test/org/apache/solr/search/CursorMarkTest.java
index ee03fcd459f..b9ab7842a1d 100644
--- a/solr/core/src/test/org/apache/solr/search/CursorMarkTest.java
+++ b/solr/core/src/test/org/apache/solr/search/CursorMarkTest.java
@@ -253,7 +253,7 @@ public class CursorMarkTest extends SolrTestCaseJ4 {
         } else if (fieldName.startsWith("bool")) {
           val = sf.getType().unmarshalSortValue(random().nextBoolean() ? "t" : "f");
         } else if (fieldName.startsWith("enum")) {
-          val = random().nextInt(CursorPagingTest.SEVERITY_ENUM_VALUES.length);
+          val = random().nextInt(CursorPagingTest.SEVERITY_ENUM_VALUES.size());
         } else if (fieldName.contains("collation")) {
           val = getRandomCollation(sf);
         } else {
diff --git a/solr/core/src/test/org/apache/solr/spelling/ConjunctionSolrSpellCheckerTest.java b/solr/core/src/test/org/apache/solr/spelling/ConjunctionSolrSpellCheckerTest.java
index e58c1e8bf6b..81feaf40664 100644
--- a/solr/core/src/test/org/apache/solr/spelling/ConjunctionSolrSpellCheckerTest.java
+++ b/solr/core/src/test/org/apache/solr/spelling/ConjunctionSolrSpellCheckerTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.spelling;
 
+import java.util.List;
 import org.apache.lucene.search.spell.JaroWinklerDistance;
 import org.apache.lucene.search.spell.LevenshteinDistance;
 import org.apache.lucene.search.spell.LuceneLevenshteinDistance;
@@ -28,19 +29,18 @@ import org.junit.Test;
 
 public class ConjunctionSolrSpellCheckerTest extends SolrTestCase {
 
-  public static final Class<?>[] AVAILABLE_DISTANCES = {
-    LevenshteinDistance.class,
-    LuceneLevenshteinDistance.class,
-    JaroWinklerDistance.class,
-    NGramDistance.class
-  };
+  public static final List<Class<? extends StringDistance>> AVAILABLE_DISTANCES =
+      List.of(
+          LevenshteinDistance.class,
+          LuceneLevenshteinDistance.class,
+          JaroWinklerDistance.class,
+          NGramDistance.class);
 
   @Test
   public void test() throws Exception {
     ConjunctionSolrSpellChecker cssc = new ConjunctionSolrSpellChecker();
-    @SuppressWarnings("unchecked")
-    Class<StringDistance> sameDistance =
-        (Class<StringDistance>) AVAILABLE_DISTANCES[random().nextInt(AVAILABLE_DISTANCES.length)];
+    Class<? extends StringDistance> sameDistance =
+        AVAILABLE_DISTANCES.get(random().nextInt(AVAILABLE_DISTANCES.size()));
 
     StringDistance sameDistance1 = sameDistance.getConstructor().newInstance();
     StringDistance sameDistance2 = sameDistance.getConstructor().newInstance();
diff --git a/solr/modules/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java b/solr/modules/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
index 10905adb978..7ef790b60cf 100644
--- a/solr/modules/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
+++ b/solr/modules/analytics/src/java/org/apache/solr/analytics/facet/SortableFacet.java
@@ -81,7 +81,6 @@ public abstract class SortableFacet extends AnalyticsFacet {
     }
     Comparator<FacetBucket> comp = sort.getComparator();
     facetResults.sort(comp);
-
     // apply the limit
     if (sort.getLimit() > 0) {
       if (sort.getOffset() > 0) {
diff --git a/solr/modules/analytics/src/test/org/apache/solr/analytics/legacy/facet/LegacyAbstractAnalyticsFacetTest.java b/solr/modules/analytics/src/test/org/apache/solr/analytics/legacy/facet/LegacyAbstractAnalyticsFacetTest.java
index 3ac1f46b1c9..17dbc293d0f 100644
--- a/solr/modules/analytics/src/test/org/apache/solr/analytics/legacy/facet/LegacyAbstractAnalyticsFacetTest.java
+++ b/solr/modules/analytics/src/test/org/apache/solr/analytics/legacy/facet/LegacyAbstractAnalyticsFacetTest.java
@@ -310,7 +310,7 @@ public class LegacyAbstractAnalyticsFacetTest extends SolrTestCaseJ4 {
         Stream.concat(Arrays.stream(BASEPARMS), Arrays.stream(args)).toArray(String[]::new));
   }
 
-  public static final String[] BASEPARMS =
+  private static final String[] BASEPARMS =
       new String[] {"q", "*:*", "indent", "true", "olap", "true", "rows", "0"};
 
   public static String[] fileToStringArr(Class<?> clazz, String fileName)
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java b/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
index 6abff958f77..ddd984cc689 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/JsonTextWriter.java
@@ -26,9 +26,11 @@ import org.apache.solr.common.IteratorWriter;
 import org.apache.solr.common.MapWriter;
 
 public interface JsonTextWriter extends TextWriter {
+  @SuppressWarnings("MutablePublicArray")
   char[] hexdigits = {
     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
   };
+
   String JSON_NL_MAP = "map";
   String JSON_NL_FLAT = "flat";
   String JSON_NL_ARROFARR = "arrarr";
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/StrUtils.java b/solr/solrj/src/java/org/apache/solr/common/util/StrUtils.java
index 684894d5422..e89eb9e9e48 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/StrUtils.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/StrUtils.java
@@ -27,6 +27,7 @@ import org.apache.solr.common.SolrException;
 
 /** */
 public class StrUtils {
+  @SuppressWarnings("MutablePublicArray")
   public static final char[] HEX_DIGITS = {
     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
   };
diff --git a/solr/solrj/src/java/org/noggit/JSONUtil.java b/solr/solrj/src/java/org/noggit/JSONUtil.java
index 108f502ffc1..5d7708fb25d 100644
--- a/solr/solrj/src/java/org/noggit/JSONUtil.java
+++ b/solr/solrj/src/java/org/noggit/JSONUtil.java
@@ -17,11 +17,12 @@
 package org.noggit;
 
 public class JSONUtil {
-  public static final char[] TRUE_CHARS = new char[] {'t', 'r', 'u', 'e'};
-  public static final char[] FALSE_CHARS = new char[] {'f', 'a', 'l', 's', 'e'};
-  public static final char[] NULL_CHARS = new char[] {'n', 'u', 'l', 'l'};
-  public static final char[] HEX_CHARS =
+  static final char[] TRUE_CHARS = new char[] {'t', 'r', 'u', 'e'};
+  static final char[] FALSE_CHARS = new char[] {'f', 'a', 'l', 's', 'e'};
+  static final char[] NULL_CHARS = new char[] {'n', 'u', 'l', 'l'};
+  static final char[] HEX_CHARS =
       new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
   public static final char VALUE_SEPARATOR = ',';
   public static final char NAME_SEPARATOR = ':';
   public static final char OBJECT_START = '{';