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/23 21:13:21 UTC

[solr] branch branch_9x updated: SOLR-16716: Replace commons-io usages with pure Java (#1478)

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


The following commit(s) were added to refs/heads/branch_9x by this push:
     new 719e7f4f3b4 SOLR-16716: Replace commons-io usages with pure Java (#1478)
719e7f4f3b4 is described below

commit 719e7f4f3b429573b051084fd0a53977a9e3e4b8
Author: Kevin Risden <ri...@users.noreply.github.com>
AuthorDate: Thu Mar 23 12:44:50 2023 -0400

    SOLR-16716: Replace commons-io usages with pure Java (#1478)
    
    Replaces commons-io with JDK methods where possible. Adds the following forbiddenapi rules.
    
    @defaultMessage Use java.nio.file.Files#copy(java.nio.file.Path, java.nio.file.Path) instead
    org.apache.commons.io.FileUtils#copyFile(java.io.File, java.io.File)
    
    @defaultMessage Use Files.readString instead
    org.apache.commons.io.FileUtils#readFileToString(**)
    
    @defaultMessage Use OutputStream.nullOutputStream() instead
    org.apache.commons.io.output.NullPrintStream
    
    @defaultMessage Use org.apache.solr.common.util.IOUtils.closeQuietly or try-with-resources
    org.apache.commons.io.IOUtils#closeQuietly(**)
    
    @defaultMessage Use new String(inputstream.readAllBytes(), StandardCharsets.UTF_8)
    org.apache.commons.io.IOUtils#toString(java.io.InputStream, java.lang.String)
    
    @defaultMessage Use readAllBytes() method on InputStream
    org.apache.commons.io.IOUtils#toByteArray(java.io.InputStream)
    org.apache.commons.io.IOUtils#toByteArray(java.net.URL)
    
    ---------
    
    Co-authored-by: David Smiley <ds...@salesforce.com>
---
 .../forbidden-apis/commons-io.commons-io.all.txt   |  19 ++++
 solr/CHANGES.txt                                   |   2 +
 .../org/apache/solr/bench/MiniClusterState.java    |   9 +-
 .../client/solrj/embedded/EmbeddedSolrServer.java  |  11 +-
 .../java/org/apache/solr/cloud/ConfigSetCmds.java  |   7 +-
 .../OverseerCollectionConfigSetProcessor.java      |   2 +-
 .../apache/solr/cloud/OverseerTaskProcessor.java   |   2 +-
 .../core/src/java/org/apache/solr/cloud/ZkCLI.java |  61 ++++-------
 .../org/apache/solr/core/ConfigSetProperties.java  |  15 +--
 .../java/org/apache/solr/core/CoreDescriptor.java  |  13 +--
 .../java/org/apache/solr/core/SolrXmlConfig.java   |   3 +-
 .../handler/DocumentAnalysisRequestHandler.java    |   7 +-
 .../apache/solr/handler/DumpRequestHandler.java    |   5 +-
 .../solr/handler/FieldAnalysisRequestHandler.java  |   6 +-
 .../java/org/apache/solr/handler/IndexFetcher.java |  16 +--
 .../apache/solr/handler/ReplicationHandler.java    |   4 -
 .../solr/handler/admin/CollectionsHandler.java     |  19 ++--
 .../handler/configsets/UploadConfigSetAPI.java     |   4 +-
 .../handler/configsets/UploadConfigSetFileAPI.java |   3 +-
 .../apache/solr/handler/loader/CSVLoaderBase.java  |  31 +++---
 .../org/apache/solr/handler/loader/JsonLoader.java |  24 ++---
 .../org/apache/solr/handler/loader/XMLLoader.java  |  36 +++----
 .../apache/solr/packagemanager/PackageUtils.java   |   6 +-
 .../solr/packagemanager/RepositoryManager.java     |   6 +-
 .../apache/solr/response/BinaryResponseWriter.java |  24 +++--
 .../org/apache/solr/schema/CollationField.java     |  10 +-
 .../solr/schema/ManagedIndexSchemaFactory.java     |   8 +-
 .../apache/solr/servlet/LoadAdminUiServlet.java    |  30 +++---
 .../HTMLStripFieldUpdateProcessorFactory.java      |   7 +-
 .../update/processor/RegexpBoostProcessor.java     |  10 +-
 .../src/java/org/apache/solr/util/SolrCLI.java     |   2 +-
 .../test/org/apache/solr/SolrTestCaseJ4Test.java   |  19 ++--
 .../org/apache/solr/TestSolrCoreProperties.java    |  51 ++++-----
 .../test/org/apache/solr/TestTolerantSearch.java   |  19 ++--
 .../org/apache/solr/cloud/SolrXmlInZkTest.java     |   7 +-
 .../org/apache/solr/cloud/TestCloudRecovery.java   |  12 +--
 .../org/apache/solr/cloud/TestConfigSetsAPI.java   |   7 +-
 .../src/test/org/apache/solr/cloud/ZkCLITest.java  |  40 +++----
 .../test/org/apache/solr/core/TestConfigSets.java  |  18 ++--
 .../org/apache/solr/core/TestCoreContainer.java    |  33 +++---
 .../org/apache/solr/core/TestCoreDiscovery.java    |  28 +++--
 .../test/org/apache/solr/core/TestLazyCores.java   |  19 ++--
 .../solr/handler/PingRequestHandlerTest.java       |   4 +-
 .../apache/solr/handler/ReplicationTestHelper.java |  12 +--
 .../org/apache/solr/handler/TestCSVLoader.java     |  14 +--
 .../apache/solr/handler/TestContainerPlugin.java   |   6 +-
 .../solr/handler/TestReplicationHandlerBackup.java |  11 +-
 .../org/apache/solr/handler/V2StandaloneTest.java  |  15 +--
 .../handler/admin/CoreAdminCreateDiscoverTest.java |  67 ++++++------
 .../solr/handler/admin/CoreAdminHandlerTest.java   | 116 +++++++++++----------
 .../component/QueryElevationComponentTest.java     |  25 +++--
 .../solr/handler/tagger/XmlInterpolationTest.java  |   9 +-
 .../reporters/SolrGraphiteReporterTest.java        |   5 +-
 .../metrics/reporters/SolrSlf4jReporterTest.java   |   6 +-
 .../apache/solr/request/TestRemoteStreaming.java   |  13 +--
 .../apache/solr/response/TestRawTransformer.java   |  26 +++--
 .../transform/TestSubQueryTransformer.java         |   2 +-
 .../solr/schema/ExternalFileFieldSortTest.java     |   7 +-
 .../org/apache/solr/schema/TestBinaryField.java    |  39 +++----
 .../org/apache/solr/schema/TestCollationField.java |  37 ++++---
 .../solr/schema/TestCollationFieldDocValues.java   |  37 ++++---
 .../org/apache/solr/schema/TestManagedSchema.java  |  29 +++---
 .../solr/search/function/TestFunctionQuery.java    |  21 ++--
 .../solr/security/AuditLoggerIntegrationTest.java  |  14 +--
 .../solr/security/BasicAuthIntegrationTest.java    |   3 +-
 .../apache/solr/security/MultiAuthPluginTest.java  |   6 +-
 .../org/apache/solr/servlet/CacheHeaderTest.java   |  13 +--
 .../apache/solr/servlet/ResponseHeaderTest.java    |  11 +-
 .../apache/solr/servlet/SolrRequestParserTest.java |   9 +-
 .../org/apache/solr/update/AddBlockUpdateTest.java |   2 +-
 .../org/apache/solr/util/TestSystemIdResolver.java |   2 +-
 solr/modules/analysis-extras/build.gradle          |   2 +-
 .../org/apache/solr/schema/ICUCollationField.java  |   9 +-
 .../apache/solr/schema/TestICUCollationField.java  |  31 +++---
 .../schema/TestICUCollationFieldDocValues.java     |  28 +++--
 solr/modules/extraction/build.gradle               |   1 -
 .../extraction/ExtractingDocumentLoader.java       |   7 +-
 .../collections/TestHdfsCloudBackupRestore.java    |   2 +-
 .../hdfs/handler/TestHdfsBackupRestoreCore.java    |   2 +-
 solr/modules/jwt-auth/build.gradle                 |   1 -
 .../apache/solr/security/jwt/JWTAuthPlugin.java    |   5 +-
 .../apache/solr/security/jwt/JWTIssuerConfig.java  |   3 +-
 .../security/jwt/JWTAuthPluginIntegrationTest.java |   3 +-
 .../solr/security/jwt/JWTAuthPluginTest.java       |  15 +--
 .../OpenNLPLangDetectUpdateProcessorFactory.java   |   9 +-
 .../org/apache/solr/s3/AbstractS3ClientTest.java   |   5 +-
 .../org/apache/solr/s3/S3OutputStreamTest.java     |  27 +++--
 .../test/org/apache/solr/s3/S3ReadWriteTest.java   |  16 +--
 .../update/ScriptUpdateProcessorFactory.java       |  10 +-
 .../solr/scripting/xslt/TransformerProvider.java   |   2 +-
 .../prometheus/exporter/SolrExporterTestBase.java  |   2 +-
 .../solr/client/solrj/TestLBHttp2SolrClient.java   |  13 +--
 .../solr/client/solrj/TestLBHttpSolrClient.java    |  13 +--
 .../solr/client/solrj/TestSolrJErrorHandling.java  |   3 +-
 .../client/solrj/embedded/JettyWebappTest.java     |  24 +++--
 .../solr/client/solrj/impl/HttpClientUtilTest.java |  13 ++-
 .../solrj/response/NoOpResponseParserTest.java     |  15 ++-
 .../response/TestDelegationTokenResponse.java      |   6 +-
 .../apache/solr/common/util/ContentStreamTest.java |   2 +-
 .../apache/solr/common/util/TestJavaBinCodec.java  |  30 +++---
 .../apache/solr/BaseDistributedSearchTestCase.java |   6 +-
 .../src/java/org/apache/solr/SolrTestCaseJ4.java   |   2 +-
 .../org/apache/solr/embedded/JettySolrRunner.java  |   4 +-
 .../apache/solr/handler/BackupRestoreUtils.java    |  11 +-
 .../apache/solr/handler/TestRestoreCoreUtil.java   |  13 +--
 105 files changed, 715 insertions(+), 836 deletions(-)

diff --git a/gradle/validation/forbidden-apis/commons-io.commons-io.all.txt b/gradle/validation/forbidden-apis/commons-io.commons-io.all.txt
index af75d00bedc..8ca8403272b 100644
--- a/gradle/validation/forbidden-apis/commons-io.commons-io.all.txt
+++ b/gradle/validation/forbidden-apis/commons-io.commons-io.all.txt
@@ -2,5 +2,24 @@
 org.apache.commons.io.IOUtils#copy(**)
 org.apache.commons.io.IOUtils#copyLarge(**)
 
+@defaultMessage Use java.nio.file.Files#copy(java.nio.file.Path, java.nio.file.Path) instead
+org.apache.commons.io.FileUtils#copyFile(java.io.File, java.io.File)
+
 @defaultMessage Use org.apache.commons.io.file.PathUtils#deleteDirectory(java.nio.file.Path) instead
 org.apache.commons.io.FileUtils#deleteDirectory(java.io.File)
+
+@defaultMessage Use Files.readString instead
+org.apache.commons.io.FileUtils#readFileToString(**)
+
+@defaultMessage Use OutputStream.nullOutputStream() instead
+org.apache.commons.io.output.NullPrintStream
+
+@defaultMessage Use org.apache.solr.common.util.IOUtils.closeQuietly or try-with-resources
+org.apache.commons.io.IOUtils#closeQuietly(**)
+
+@defaultMessage Use new String(inputstream.readAllBytes(), StandardCharsets.UTF_8)
+org.apache.commons.io.IOUtils#toString(java.io.InputStream, java.lang.String)
+
+@defaultMessage Use readAllBytes() method on InputStream
+org.apache.commons.io.IOUtils#toByteArray(java.io.InputStream)
+org.apache.commons.io.IOUtils#toByteArray(java.net.URL)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 7a1d6a47e3c..2f290ea3a28 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -46,6 +46,8 @@ Other Changes
 
 * SOLR-16713: Replace Guava usages with pure Java (Kevin Risden)
 
+* SOLR-16716: Replace commons-io usages with pure Java (Kevin Risden)
+
 ==================  9.2.0 ==================
 
 New Features
diff --git a/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java b/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
index 2e2e1c0e44b..cbc30cb5a11 100755
--- a/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
@@ -22,9 +22,12 @@ import static org.apache.solr.bench.BaseBenchState.log;
 import com.codahale.metrics.Meter;
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
 import java.lang.invoke.MethodHandles;
 import java.lang.management.ManagementFactory;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -35,7 +38,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.output.NullPrintStream;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
@@ -463,7 +465,10 @@ public class MiniClusterState {
      */
     @SuppressForbidden(reason = "JMH uses std out for user output")
     public void dumpCoreInfo() throws IOException {
-      cluster.dumpCoreInfo(!BaseBenchState.QUIET_LOG ? System.out : new NullPrintStream());
+      cluster.dumpCoreInfo(
+          !BaseBenchState.QUIET_LOG
+              ? System.out
+              : new PrintStream(OutputStream.nullOutputStream(), false, StandardCharsets.UTF_8));
     }
   }
 
diff --git a/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java b/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
index 3593f5eb376..5a55aaa1fd3 100644
--- a/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
+++ b/solr/core/src/java/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
@@ -19,6 +19,7 @@ package org.apache.solr.client.solrj.embedded;
 import static org.apache.solr.common.params.CommonParams.PATH;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Path;
@@ -28,7 +29,6 @@ import java.util.HashSet;
 import java.util.Properties;
 import java.util.Set;
 import java.util.function.Supplier;
-import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.lucene.search.TotalHits.Relation;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrRequest;
@@ -246,12 +246,17 @@ public class EmbeddedSolrServer extends SolrClient {
                 }
               };
 
-          try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+          try (var out =
+              new ByteArrayOutputStream() {
+                ByteArrayInputStream toInputStream() {
+                  return new ByteArrayInputStream(buf, 0, count);
+                }
+              }) {
             createJavaBinCodec(callback, resolver)
                 .setWritableDocFields(resolver)
                 .marshal(rsp.getValues(), out);
 
-            try (InputStream in = out.toInputStream()) {
+            try (ByteArrayInputStream in = out.toInputStream()) {
               @SuppressWarnings({"unchecked"})
               NamedList<Object> resolved =
                   (NamedList<Object>) new JavaBinCodec(resolver).unmarshal(in);
diff --git a/solr/core/src/java/org/apache/solr/cloud/ConfigSetCmds.java b/solr/core/src/java/org/apache/solr/cloud/ConfigSetCmds.java
index cb0e62fe29f..ee1c01f99d4 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ConfigSetCmds.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ConfigSetCmds.java
@@ -70,12 +70,9 @@ public class ConfigSetCmds {
       throws IOException {
     byte[] oldPropsData = configSetService.downloadFileFromConfig(configName, propertyPath);
     if (oldPropsData != null) {
-      InputStreamReader reader =
-          new InputStreamReader(new ByteArrayInputStream(oldPropsData), StandardCharsets.UTF_8);
-      try {
+      try (InputStreamReader reader =
+          new InputStreamReader(new ByteArrayInputStream(oldPropsData), StandardCharsets.UTF_8)) {
         return ConfigSetProperties.readFromInputStream(reader);
-      } finally {
-        reader.close();
       }
     }
     return null;
diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionConfigSetProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionConfigSetProcessor.java
index b93f9b1688b..9536a09b6d5 100644
--- a/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionConfigSetProcessor.java
+++ b/solr/core/src/java/org/apache/solr/cloud/OverseerCollectionConfigSetProcessor.java
@@ -19,10 +19,10 @@ package org.apache.solr.cloud;
 import static org.apache.solr.cloud.OverseerConfigSetMessageHandler.CONFIGSETS_ACTION_PREFIX;
 
 import java.io.IOException;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.cloud.api.collections.OverseerCollectionMessageHandler;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.handler.component.HttpShardHandler;
 import org.apache.solr.handler.component.HttpShardHandlerFactory;
 import org.apache.solr.metrics.SolrMetricsContext;
diff --git a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java
index e249e013895..14685e8b26c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java
+++ b/solr/core/src/java/org/apache/solr/cloud/OverseerTaskProcessor.java
@@ -34,7 +34,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.cloud.Overseer.LeaderStatus;
 import org.apache.solr.cloud.OverseerTaskQueue.QueueEvent;
 import org.apache.solr.common.AlreadyClosedException;
@@ -43,6 +42,7 @@ import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java b/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java
index 9cac8e45661..11333809a70 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkCLI.java
@@ -21,12 +21,11 @@ import static org.apache.solr.common.params.CommonParams.VALUE_LONG;
 
 import com.google.common.annotations.VisibleForTesting;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintStream;
 import java.lang.reflect.InvocationTargetException;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
@@ -42,8 +41,6 @@ import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.PosixParser;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.StringUtils;
 import org.apache.solr.common.cloud.ClusterProperties;
@@ -299,17 +296,14 @@ public class ZkCLI implements CLIO {
         }
       }
 
-      SolrZkClient zkClient = null;
-      try {
-        zkClient =
-            new SolrZkClient.Builder()
-                .withUrl(zkServerAddress)
-                .withTimeout(30000, TimeUnit.MILLISECONDS)
-                .withConnTimeOut(30000, TimeUnit.MILLISECONDS)
-                .withReconnectListener(() -> {})
-                .withCompressor(compressor)
-                .build();
-
+      try (SolrZkClient zkClient =
+          new SolrZkClient.Builder()
+              .withUrl(zkServerAddress)
+              .withTimeout(30000, TimeUnit.MILLISECONDS)
+              .withConnTimeOut(30000, TimeUnit.MILLISECONDS)
+              .withReconnectListener(() -> {})
+              .withCompressor(compressor)
+              .build()) {
         if (line.getOptionValue(CMD).equalsIgnoreCase(BOOTSTRAP)) {
           if (!line.hasOption(SOLRHOME)) {
             stdout.println("-" + SOLRHOME + " is required for " + BOOTSTRAP);
@@ -378,9 +372,9 @@ public class ZkCLI implements CLIO {
           }
 
           StringBuilder sb = new StringBuilder();
-          String path = argList.get(0).toString();
+          String path = argList.get(0);
           zkClient.printLayout(path == null ? "/" : path, 0, sb);
-          stdout.println(sb.toString());
+          stdout.println(sb);
 
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(CLEAR)) {
           List<String> arglist = line.getArgList();
@@ -388,14 +382,14 @@ public class ZkCLI implements CLIO {
             stdout.println("-" + CLEAR + " requires one arg - the path to clear");
             System.exit(1);
           }
-          zkClient.clean(arglist.get(0).toString());
+          zkClient.clean(arglist.get(0));
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(MAKEPATH)) {
           List<String> arglist = line.getArgList();
           if (arglist.size() != 1) {
             stdout.println("-" + MAKEPATH + " requires one arg - the path to make");
             System.exit(1);
           }
-          zkClient.makePath(arglist.get(0).toString(), true);
+          zkClient.makePath(arglist.get(0), true);
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(PUT)) {
           List<String> arglist = line.getArgList();
           if (arglist.size() != 2) {
@@ -424,30 +418,24 @@ public class ZkCLI implements CLIO {
             System.exit(1);
           }
 
-          String path = arglist.get(0).toString();
-          InputStream is = new FileInputStream(arglist.get(1).toString());
-          byte[] data = IOUtils.toByteArray(is);
+          String path = arglist.get(0);
+          byte[] data = Files.readAllBytes(Path.of(arglist.get(1)));
           if (shouldCompressData(data, path, minStateByteLenForCompression)) {
             // state.json should be compressed before being put to ZK
             data = compressor.compressBytes(data);
           }
-          try {
-            if (zkClient.exists(path, true)) {
-              zkClient.setData(path, data, true);
-            } else {
-              zkClient.create(path, data, CreateMode.PERSISTENT, true);
-            }
-          } finally {
-            IOUtils.closeQuietly(is);
+          if (zkClient.exists(path, true)) {
+            zkClient.setData(path, data, true);
+          } else {
+            zkClient.create(path, data, CreateMode.PERSISTENT, true);
           }
-
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(GET)) {
           List<String> arglist = line.getArgList();
           if (arglist.size() != 1) {
             stdout.println("-" + GET + " requires one arg - the path to get");
             System.exit(1);
           }
-          byte[] data = zkClient.getData(arglist.get(0).toString(), null, null, true);
+          byte[] data = zkClient.getData(arglist.get(0), null, null, true);
           stdout.println(new String(data, StandardCharsets.UTF_8));
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(GET_FILE)) {
           List<String> arglist = line.getArgList();
@@ -456,15 +444,15 @@ public class ZkCLI implements CLIO {
                 "-" + GET_FILE + "requires two args - the path to get and the file to save it to");
             System.exit(1);
           }
-          byte[] data = zkClient.getData(arglist.get(0).toString(), null, null, true);
-          FileUtils.writeByteArrayToFile(new File(arglist.get(1).toString()), data);
+          byte[] data = zkClient.getData(arglist.get(0), null, null, true);
+          Files.write(Path.of(arglist.get(1)), data);
         } else if (line.getOptionValue(CMD).equals(UPDATEACLS)) {
           List<String> arglist = line.getArgList();
           if (arglist.size() != 1) {
             stdout.println("-" + UPDATEACLS + " requires one arg - the path to update");
             System.exit(1);
           }
-          zkClient.updateACLs(arglist.get(0).toString());
+          zkClient.updateACLs(arglist.get(0));
         } else if (line.getOptionValue(CMD).equalsIgnoreCase(CLUSTERPROP)) {
           if (!line.hasOption(NAME)) {
             stdout.println("-" + NAME + " is required for " + CLUSTERPROP);
@@ -491,9 +479,6 @@ public class ZkCLI implements CLIO {
         if (solrPort != null) {
           zkServer.stop();
         }
-        if (zkClient != null) {
-          zkClient.close();
-        }
       }
     } catch (ParseException exp) {
       stdout.println("Unexpected exception:" + exp.getMessage());
diff --git a/solr/core/src/java/org/apache/solr/core/ConfigSetProperties.java b/solr/core/src/java/org/apache/solr/core/ConfigSetProperties.java
index 0ebfff643e3..9afe3e8ae96 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigSetProperties.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigSetProperties.java
@@ -20,7 +20,6 @@ import java.io.InputStreamReader;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.util.NamedList;
@@ -50,9 +49,9 @@ public class ConfigSetProperties {
    * @return the properties in a NamedList
    */
   public static NamedList<Object> readFromResourceLoader(SolrResourceLoader loader, String name) {
-    InputStreamReader reader;
-    try {
-      reader = new InputStreamReader(loader.openResource(name), StandardCharsets.UTF_8);
+    try (InputStreamReader reader =
+        new InputStreamReader(loader.openResource(name), StandardCharsets.UTF_8)) {
+      return readFromInputStream(reader);
     } catch (SolrResourceNotFoundException ex) {
       if (log.isDebugEnabled()) {
         log.debug("Did not find ConfigSet properties, assuming default properties: ", ex);
@@ -62,12 +61,6 @@ public class ConfigSetProperties {
       throw new SolrException(
           ErrorCode.SERVER_ERROR, "Unable to load reader for ConfigSet properties: " + name, ex);
     }
-
-    try {
-      return readFromInputStream(reader);
-    } finally {
-      IOUtils.closeQuietly(reader);
-    }
   }
 
   public static NamedList<Object> readFromInputStream(InputStreamReader reader) {
@@ -83,8 +76,6 @@ public class ConfigSetProperties {
       return new NamedList<>(map);
     } catch (Exception ex) {
       throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to load ConfigSet properties", ex);
-    } finally {
-      IOUtils.closeQuietly(reader);
     }
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java b/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java
index 21234d81315..bc65919417d 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreDescriptor.java
@@ -18,8 +18,7 @@ package org.apache.solr.core;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.io.Reader;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -242,17 +241,13 @@ public class CoreDescriptor {
     String filename = coreProperties.getProperty(CORE_PROPERTIES, DEFAULT_EXTERNAL_PROPERTIES_FILE);
     Path propertiesFile = instanceDir.resolve(filename);
     if (Files.exists(propertiesFile)) {
-      try (InputStream is = Files.newInputStream(propertiesFile)) {
+      try (Reader r = Files.newBufferedReader(propertiesFile, StandardCharsets.UTF_8)) {
         Properties externalProps = new Properties();
-        externalProps.load(new InputStreamReader(is, StandardCharsets.UTF_8));
+        externalProps.load(r);
         coreProperties.putAll(externalProps);
       } catch (IOException e) {
         String message =
-            String.format(
-                Locale.ROOT,
-                "Could not load properties from %s: %s:",
-                propertiesFile.toString(),
-                e.toString());
+            String.format(Locale.ROOT, "Could not load properties from %s: %s:", propertiesFile, e);
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, message);
       }
     }
diff --git a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
index 5a10d7fce0c..821b6e8ba4f 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrXmlConfig.java
@@ -37,7 +37,6 @@ import java.util.function.Consumer;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import javax.management.MBeanServer;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.common.ConfigNode;
@@ -228,7 +227,7 @@ public class SolrXmlConfig {
       substituteProps = new Properties();
     }
     try {
-      byte[] buf = IOUtils.toByteArray(is);
+      byte[] buf = is.readAllBytes();
       try (ByteArrayInputStream dup = new ByteArrayInputStream(buf)) {
         XmlConfigFile config =
             new XmlConfigFile(loader, null, new InputSource(dup), null, substituteProps);
diff --git a/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java
index 7b7122fbfed..85073e37fc7 100644
--- a/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java
@@ -28,7 +28,6 @@ import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.util.BytesRef;
 import org.apache.solr.client.solrj.request.DocumentAnalysisRequest;
@@ -145,11 +144,9 @@ public class DocumentAnalysisRequestHandler extends AnalysisRequestHandlerBase {
     request.setShowMatch(showMatch);
 
     ContentStream stream = extractSingleContentStream(req);
-    InputStream is = null;
     XMLStreamReader parser = null;
 
-    try {
-      is = stream.getStream();
+    try (InputStream is = stream.getStream()) {
       final String charset = ContentStreamBase.getCharsetFromContentType(stream.getContentType());
       parser =
           (charset == null)
@@ -176,10 +173,8 @@ public class DocumentAnalysisRequestHandler extends AnalysisRequestHandlerBase {
             }
         }
       }
-
     } finally {
       if (parser != null) parser.close();
-      IOUtils.closeQuietly(is);
     }
   }
 
diff --git a/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
index 73dced2832d..eea1bebc0cd 100644
--- a/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
@@ -92,11 +92,8 @@ public class DumpRequestHandler extends RequestHandlerBase implements SolrCoreAw
         stream.add("sourceInfo", content.getSourceInfo());
         stream.add("size", content.getSize());
         stream.add("contentType", content.getContentType());
-        Reader reader = content.getReader();
-        try {
+        try (Reader reader = content.getReader()) {
           stream.add("stream", IOUtils.toString(reader));
-        } finally {
-          reader.close();
         }
         streams.add(stream);
       }
diff --git a/solr/core/src/java/org/apache/solr/handler/FieldAnalysisRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/FieldAnalysisRequestHandler.java
index 12778d9eea7..d5dca872b58 100644
--- a/solr/core/src/java/org/apache/solr/handler/FieldAnalysisRequestHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/FieldAnalysisRequestHandler.java
@@ -153,14 +153,10 @@ public class FieldAnalysisRequestHandler extends AnalysisRequestHandlerBase {
     if (streams != null) {
       // NOTE: Only the first content stream is currently processed
       for (ContentStream stream : streams) {
-        Reader reader = null;
-        try {
-          reader = stream.getReader();
+        try (Reader reader = stream.getReader()) {
           value = IOUtils.toString(reader);
         } catch (IOException e) {
           // do nothing, leave value set to the request parameter
-        } finally {
-          IOUtils.closeQuietly(reader);
         }
         break;
       }
diff --git a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
index d3bcfb084dc..d03871d9ec5 100644
--- a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
+++ b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
@@ -972,13 +972,10 @@ public class IndexFetcher {
 
       String tmpFileName = REPLICATION_PROPERTIES + "." + System.nanoTime();
       final IndexOutput out = dir.createOutput(tmpFileName, DirectoryFactory.IOCONTEXT_NO_CACHE);
-      Writer outFile =
-          new OutputStreamWriter(new PropertiesOutputStream(out), StandardCharsets.UTF_8);
-      try {
+      try (Writer outFile =
+          new OutputStreamWriter(new PropertiesOutputStream(out), StandardCharsets.UTF_8)) {
         props.store(outFile, "Replication details");
         dir.sync(Collections.singleton(tmpFileName));
-      } finally {
-        IOUtils.closeQuietly(outFile);
       }
 
       solrCore.getDirectoryFactory().renameWithOverwrite(dir, tmpFileName, REPLICATION_PROPERTIES);
@@ -1794,18 +1791,14 @@ public class IndexFetcher {
     private void fetch() throws Exception {
       try {
         while (true) {
-          final FastInputStream is = getStream();
           int result;
-          try {
+          try (FastInputStream is = getStream()) {
             // fetch packets one by one in a single request
             result = fetchPackets(is);
             if (result == 0 || result == NO_CONTENT) {
-
               return;
             }
             // if there is an error continue. But continue from the point where it got broken
-          } finally {
-            IOUtils.closeQuietly(is);
           }
         }
       } finally {
@@ -1959,7 +1952,6 @@ public class IndexFetcher {
 
     /** Open a new stream using HttpClient */
     private FastInputStream getStream() throws IOException {
-
       ModifiableSolrParams params = new ModifiableSolrParams();
 
       //    //the method is command=filecontent
@@ -2003,7 +1995,7 @@ public class IndexFetcher {
         return new FastInputStream(is);
       } catch (Exception e) {
         // close stream on error
-        org.apache.commons.io.IOUtils.closeQuietly(is);
+        IOUtils.closeQuietly(is);
         throw new IOException("Could not download file '" + fileName + "'", e);
       }
     }
diff --git a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
index 7cae4115598..eebb00023c3 100644
--- a/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/ReplicationHandler.java
@@ -18,7 +18,6 @@ package org.apache.solr.handler;
 
 import static org.apache.solr.common.params.CommonParams.NAME;
 
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -56,7 +55,6 @@ import java.util.regex.Pattern;
 import java.util.zip.Adler32;
 import java.util.zip.Checksum;
 import java.util.zip.DeflaterOutputStream;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.CloseShieldOutputStream;
 import org.apache.lucene.codecs.CodecUtil;
 import org.apache.lucene.index.DirectoryReader;
@@ -1761,7 +1759,6 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
     @Override
     public void write(OutputStream out) throws IOException {
       createOutputStream(out);
-      FileInputStream inputStream = null;
       try {
         initWrite();
 
@@ -1797,7 +1794,6 @@ public class ReplicationHandler extends RequestHandlerBase implements SolrCoreAw
       } catch (IOException e) {
         log.warn("Exception while writing response for params: {}", params, e);
       } finally {
-        IOUtils.closeQuietly(inputStream);
         extendReserveAndReleaseCommitPoint();
       }
     }
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 8864f45e1cb..de9f3dd9556 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
@@ -125,6 +125,7 @@ import static org.apache.solr.common.params.ShardParams._ROUTE_;
 import static org.apache.solr.common.util.StrUtils.formatString;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.lang.invoke.MethodHandles;
 import java.net.URI;
 import java.util.ArrayList;
@@ -142,7 +143,6 @@ import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.solr.api.AnnotatedApi;
 import org.apache.solr.api.Api;
@@ -550,9 +550,12 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
     try {
       String path =
           ZkStateReader.CONFIGS_ZKNODE + "/" + CollectionAdminParams.SYSTEM_COLL + "/schema.xml";
-      byte[] data =
-          IOUtils.toByteArray(
-              CollectionsHandler.class.getResourceAsStream("/SystemCollectionSchema.xml"));
+      byte[] data;
+      try (InputStream inputStream =
+          CollectionsHandler.class.getResourceAsStream("/SystemCollectionSchema.xml")) {
+        assert inputStream != null;
+        data = inputStream.readAllBytes();
+      }
       assert data != null && data.length > 0;
       cmdExecutor.ensureExists(path, data, CreateMode.PERSISTENT, zk);
       path =
@@ -560,9 +563,11 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
               + "/"
               + CollectionAdminParams.SYSTEM_COLL
               + "/solrconfig.xml";
-      data =
-          IOUtils.toByteArray(
-              CollectionsHandler.class.getResourceAsStream("/SystemCollectionSolrConfig.xml"));
+      try (InputStream inputStream =
+          CollectionsHandler.class.getResourceAsStream("/SystemCollectionSolrConfig.xml")) {
+        assert inputStream != null;
+        data = inputStream.readAllBytes();
+      }
       assert data != null && data.length > 0;
       cmdExecutor.ensureExists(path, data, CreateMode.PERSISTENT, zk);
     } catch (IOException e) {
diff --git a/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetAPI.java b/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetAPI.java
index 4cb08542386..f7910bf7616 100644
--- a/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetAPI.java
@@ -28,7 +28,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.api.EndPoint;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.ConfigSetParams;
@@ -94,8 +93,7 @@ public class UploadConfigSetAPI extends ConfigSetAPIBase {
         String filePath = zipEntry.getName();
         filesToDelete.remove(filePath);
         if (!zipEntry.isDirectory()) {
-          configSetService.uploadFileToConfig(
-              configSetName, filePath, IOUtils.toByteArray(zis), true);
+          configSetService.uploadFileToConfig(configSetName, filePath, zis.readAllBytes(), true);
         }
       }
       if (!hasEntry) {
diff --git a/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetFileAPI.java b/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetFileAPI.java
index df877e2b8f8..98889aff563 100644
--- a/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetFileAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/configsets/UploadConfigSetFileAPI.java
@@ -20,7 +20,6 @@ import static org.apache.solr.client.solrj.SolrRequest.METHOD.PUT;
 import static org.apache.solr.security.PermissionNameProvider.Name.CONFIG_EDIT_PERM;
 
 import java.io.InputStream;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.api.EndPoint;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkMaintenanceUtils;
@@ -89,7 +88,7 @@ public class UploadConfigSetFileAPI extends ConfigSetAPIBase {
       // singleFilePath is not passed.
       createBaseNode(configSetService, overwritesExisting, requestIsTrusted, configSetName);
       configSetService.uploadFileToConfig(
-          configSetName, fixedSingleFilePath, IOUtils.toByteArray(inputStream), allowOverwrite);
+          configSetName, fixedSingleFilePath, inputStream.readAllBytes(), allowOverwrite);
     }
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/loader/CSVLoaderBase.java b/solr/core/src/java/org/apache/solr/handler/loader/CSVLoaderBase.java
index a91c65e30c7..f11f41e8fa3 100644
--- a/solr/core/src/java/org/apache/solr/handler/loader/CSVLoaderBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/loader/CSVLoaderBase.java
@@ -25,7 +25,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.params.SolrParams;
@@ -366,19 +365,7 @@ public abstract class CSVLoaderBase extends ContentStreamLoader {
       UpdateRequestProcessor processor)
       throws IOException {
     errHeader = "CSVLoader: input=" + stream.getSourceInfo();
-    Reader reader = null;
-    try {
-      reader = stream.getReader();
-      if (skipLines > 0) {
-        if (!(reader instanceof BufferedReader)) {
-          reader = new BufferedReader(reader);
-        }
-        BufferedReader r = (BufferedReader) reader;
-        for (int i = 0; i < skipLines; i++) {
-          r.readLine();
-        }
-      }
-
+    try (Reader reader = getReader(stream)) {
       CSVParser parser = new CSVParser(reader, strategy);
 
       // parse the fieldnames from the header of the file
@@ -409,11 +396,21 @@ public abstract class CSVLoaderBase extends ContentStreamLoader {
 
         addDoc(line, vals);
       }
-    } finally {
-      if (reader != null) {
-        IOUtils.closeQuietly(reader);
+    }
+  }
+
+  private Reader getReader(ContentStream cs) throws IOException {
+    Reader reader = cs.getReader();
+    if (skipLines > 0) {
+      if (!(reader instanceof BufferedReader)) {
+        reader = new BufferedReader(reader);
+      }
+      BufferedReader r = (BufferedReader) reader;
+      for (int i = 0; i < skipLines; i++) {
+        r.readLine();
       }
     }
+    return reader;
   }
 
   /** called for each line of values (document) */
diff --git a/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java b/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java
index d8d4ac3c570..70f62eb26b0 100644
--- a/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java
+++ b/solr/core/src/java/org/apache/solr/handler/loader/JsonLoader.java
@@ -147,25 +147,25 @@ public class JsonLoader extends ContentStreamLoader {
         ContentStream stream,
         UpdateRequestProcessor processor)
         throws Exception {
-
-      Reader reader = null;
-      try {
-        reader = stream.getReader();
-        if (log.isTraceEnabled()) {
-          String body = IOUtils.toString(reader);
-          log.trace("body: {}", body);
-          reader = new StringReader(body);
-        }
-
+      try (Reader reader = getReader(stream)) {
         this.processUpdate(reader);
       } catch (ParseException e) {
         throw new SolrException(
             SolrException.ErrorCode.BAD_REQUEST, "Cannot parse provided JSON: " + e.getMessage());
-      } finally {
-        IOUtils.closeQuietly(reader);
       }
     }
 
+    private Reader getReader(ContentStream stream) throws IOException {
+      if (log.isTraceEnabled()) {
+        try (Reader reader = stream.getReader()) {
+          String body = IOUtils.toString(reader);
+          log.trace("body: {}", body);
+          return new StringReader(body);
+        }
+      }
+      return stream.getReader();
+    }
+
     @SuppressWarnings("fallthrough")
     void processUpdate(Reader reader) throws IOException {
       String path = (String) req.getContext().get(PATH);
diff --git a/solr/core/src/java/org/apache/solr/handler/loader/XMLLoader.java b/solr/core/src/java/org/apache/solr/handler/loader/XMLLoader.java
index a48d00fceaf..5bc13f2a3ea 100644
--- a/solr/core/src/java/org/apache/solr/handler/loader/XMLLoader.java
+++ b/solr/core/src/java/org/apache/solr/handler/loader/XMLLoader.java
@@ -35,7 +35,6 @@ import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.EmptyEntityResolver;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
@@ -109,25 +108,10 @@ public class XMLLoader extends ContentStreamLoader {
       UpdateRequestProcessor processor)
       throws Exception {
     final String charset = ContentStreamBase.getCharsetFromContentType(stream.getContentType());
-
-    InputStream is = null;
     XMLStreamReader parser = null;
 
     // Normal XML Loader
-    try {
-      is = stream.getStream();
-      if (log.isTraceEnabled()) {
-        final byte[] body = IOUtils.toByteArray(is);
-        // TODO: The charset may be wrong, as the real charset is later
-        // determined by the XML parser, the content-type is only used as a hint!
-        if (log.isTraceEnabled()) {
-          log.trace(
-              "body: {}",
-              new String(body, (charset == null) ? ContentStreamBase.DEFAULT_CHARSET : charset));
-        }
-        IOUtils.closeQuietly(is);
-        is = new ByteArrayInputStream(body);
-      }
+    try (InputStream is = getStream(stream, charset)) {
       parser =
           (charset == null)
               ? inputFactory.createXMLStreamReader(is)
@@ -137,10 +121,26 @@ public class XMLLoader extends ContentStreamLoader {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e.getMessage(), e);
     } finally {
       if (parser != null) parser.close();
-      IOUtils.closeQuietly(is);
     }
   }
 
+  private InputStream getStream(ContentStream cs, String charset) throws IOException {
+    if (log.isTraceEnabled()) {
+      try (InputStream is = cs.getStream()) {
+        final byte[] body = is.readAllBytes();
+        // TODO: The charset may be wrong, as the real charset is later
+        // determined by the XML parser, the content-type is only used as a hint!
+        if (log.isTraceEnabled()) {
+          log.trace(
+              "body: {}",
+              new String(body, (charset == null) ? ContentStreamBase.DEFAULT_CHARSET : charset));
+        }
+        return new ByteArrayInputStream(body);
+      }
+    }
+    return cs.getStream();
+  }
+
   /**
    * @since solr 1.2
    */
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
index f212493da86..f6210d09da9 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
@@ -25,12 +25,12 @@ import com.jayway.jsonpath.spi.mapper.MappingProvider;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
@@ -132,7 +132,7 @@ public class PackageUtils {
       try (ZipFile zipFile = new ZipFile(jarfile.toFile())) {
         ZipEntry entry = zipFile.getEntry(filename);
         if (entry == null) continue;
-        return IOUtils.toString(zipFile.getInputStream(entry), "UTF-8");
+        return new String(zipFile.getInputStream(entry).readAllBytes(), StandardCharsets.UTF_8);
       } catch (Exception ex) {
         throw new SolrException(ErrorCode.BAD_REQUEST, ex);
       }
@@ -149,7 +149,7 @@ public class PackageUtils {
             ErrorCode.NOT_FOUND,
             "Error (code=" + resp.getStatusLine().getStatusCode() + ") fetching from URL: " + url);
       }
-      return IOUtils.toString(resp.getEntity().getContent(), "UTF-8");
+      return new String(resp.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8);
     } catch (UnsupportedOperationException | IOException e) {
       throw new RuntimeException(e);
     }
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
index d81415433ca..45d821f5cd5 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -20,6 +20,7 @@ package org.apache.solr.packagemanager;
 import static org.apache.solr.packagemanager.PackageUtils.getMapper;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.lang.invoke.MethodHandles;
 import java.net.URL;
@@ -35,7 +36,6 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.stream.Collectors;
 import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
@@ -129,7 +129,9 @@ public class RepositoryManager {
           true);
     }
 
-    addKey(IOUtils.toByteArray(new URL(uri + "/publickey.der").openStream()), repoName + ".der");
+    try (InputStream is = new URL(uri + "/publickey.der").openStream()) {
+      addKey(is.readAllBytes(), repoName + ".der");
+    }
   }
 
   public void addKey(byte[] key, String destinationKeyFilename) throws Exception {
diff --git a/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java b/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java
index 74a1f4842ae..7e248891009 100644
--- a/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java
+++ b/solr/core/src/java/org/apache/solr/response/BinaryResponseWriter.java
@@ -18,6 +18,8 @@ package org.apache.solr.response;
 
 import static org.apache.solr.common.util.ByteArrayUtf8CharSequence.convertCharSeq;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -29,7 +31,6 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Consumer;
-import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.TotalHits;
@@ -196,14 +197,21 @@ public class BinaryResponseWriter implements BinaryQueryResponseWriter {
       }
       Resolver resolver = new Resolver(req, rsp.getReturnFields());
 
-      ByteArrayOutputStream out = new ByteArrayOutputStream();
-      try (JavaBinCodec jbc = new JavaBinCodec(resolver)) {
-        jbc.setWritableDocFields(resolver).marshal(rsp.getValues(), out);
-      }
+      try (var out =
+          new ByteArrayOutputStream() {
+            ByteArrayInputStream toInputStream() {
+              return new ByteArrayInputStream(buf, 0, count);
+            }
+          }) {
+        try (JavaBinCodec jbc = new JavaBinCodec(resolver)) {
+          jbc.setWritableDocFields(resolver).marshal(rsp.getValues(), out);
+        }
 
-      InputStream in = out.toInputStream();
-      try (JavaBinCodec jbc = new JavaBinCodec(resolver)) {
-        return (NamedList<Object>) jbc.unmarshal(in);
+        try (InputStream in = out.toInputStream()) {
+          try (JavaBinCodec jbc = new JavaBinCodec(resolver)) {
+            return (NamedList<Object>) jbc.unmarshal(in);
+          }
+        }
       }
     } catch (Exception ex) {
       throw new RuntimeException(ex);
diff --git a/solr/core/src/java/org/apache/solr/schema/CollationField.java b/solr/core/src/java/org/apache/solr/schema/CollationField.java
index 3ec35de2758..25ad27f00fb 100644
--- a/solr/core/src/java/org/apache/solr/schema/CollationField.java
+++ b/solr/core/src/java/org/apache/solr/schema/CollationField.java
@@ -18,6 +18,7 @@ package org.apache.solr.schema;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.text.Collator;
 import java.text.ParseException;
 import java.text.RuleBasedCollator;
@@ -26,7 +27,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.TokenStream;
 import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute;
@@ -162,16 +162,12 @@ public class CollationField extends FieldType {
    * as # might be in the rules!
    */
   private Collator createFromRules(String fileName, ResourceLoader loader) {
-    InputStream input = null;
-    try {
-      input = loader.openResource(fileName);
-      String rules = IOUtils.toString(input, "UTF-8");
+    try (InputStream input = loader.openResource(fileName)) {
+      String rules = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       return new RuleBasedCollator(rules);
     } catch (IOException | ParseException e) {
       // io error or invalid rules
       throw new RuntimeException(e);
-    } finally {
-      IOUtils.closeQuietly(input);
     }
   }
 
diff --git a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchemaFactory.java b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchemaFactory.java
index 15db3cd9837..96cbb9d5680 100644
--- a/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchemaFactory.java
+++ b/solr/core/src/java/org/apache/solr/schema/ManagedIndexSchemaFactory.java
@@ -27,7 +27,6 @@ import java.nio.file.Paths;
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Map.Entry;
 import net.jcip.annotations.NotThreadSafe;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.cloud.ZkSolrResourceLoader;
 import org.apache.solr.common.SolrException;
@@ -35,6 +34,7 @@ import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkCmdExecutor;
 import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.ConfigSetService;
 import org.apache.solr.core.SolrConfig;
@@ -360,9 +360,7 @@ public class ManagedIndexSchemaFactory extends IndexSchemaFactory implements Sol
               "Error checking for the existence of the non-managed schema {}", resourceName, e);
         }
       } else { // Config is not in ZooKeeper
-        InputStream nonManagedSchemaInputStream = null;
-        try {
-          nonManagedSchemaInputStream = loader.openResource(resourceName);
+        try (InputStream nonManagedSchemaInputStream = loader.openResource(resourceName)) {
           if (null != nonManagedSchemaInputStream) {
             exists = true;
           }
@@ -371,8 +369,6 @@ public class ManagedIndexSchemaFactory extends IndexSchemaFactory implements Sol
         } catch (IOException e) {
           throw new RuntimeException(e);
           // This is expected when the non-managed schema does not exist
-        } finally {
-          IOUtils.closeQuietly(nonManagedSchemaInputStream);
         }
       }
       if (exists) {
diff --git a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
index ad304889cad..5a7e797f297 100644
--- a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
+++ b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
@@ -23,7 +23,6 @@ import java.io.Writer;
 import java.nio.charset.StandardCharsets;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.CloseShieldOutputStream;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrCore;
@@ -57,29 +56,24 @@ public final class LoadAdminUiServlet extends BaseSolrServlet {
     // This attribute is set by the SolrDispatchFilter
     String admin = request.getRequestURI().substring(request.getContextPath().length());
     CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
-    InputStream in = getServletContext().getResourceAsStream(admin);
-    Writer out = null;
-    if (in != null && cores != null) {
-      try {
+    try (InputStream in = getServletContext().getResourceAsStream(admin)) {
+      if (in != null && cores != null) {
         response.setCharacterEncoding("UTF-8");
         response.setContentType("text/html");
 
         // We have to close this to flush OutputStreamWriter buffer
-        out =
+        try (Writer out =
             new OutputStreamWriter(
-                CloseShieldOutputStream.wrap(response.getOutputStream()), StandardCharsets.UTF_8);
-
-        Package pack = SolrCore.class.getPackage();
-        String html =
-            IOUtils.toString(in, StandardCharsets.UTF_8)
-                .replace("${version}", pack.getSpecificationVersion());
-        out.write(html);
-      } finally {
-        IOUtils.closeQuietly(in);
-        IOUtils.closeQuietly(out);
+                CloseShieldOutputStream.wrap(response.getOutputStream()), StandardCharsets.UTF_8)) {
+          Package pack = SolrCore.class.getPackage();
+          String html =
+              new String(in.readAllBytes(), StandardCharsets.UTF_8)
+                  .replace("${version}", pack.getSpecificationVersion());
+          out.write(html);
+        }
+      } else {
+        response.sendError(404);
       }
-    } else {
-      response.sendError(404);
     }
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/update/processor/HTMLStripFieldUpdateProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/HTMLStripFieldUpdateProcessorFactory.java
index bee24d75204..b16466f42a5 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/HTMLStripFieldUpdateProcessorFactory.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/HTMLStripFieldUpdateProcessorFactory.java
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.StringWriter;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.analysis.charfilter.HTMLStripCharFilter;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.request.SolrQueryRequest;
@@ -63,16 +62,12 @@ public final class HTMLStripFieldUpdateProcessorFactory
           if (src instanceof CharSequence) {
             CharSequence s = (CharSequence) src;
             StringWriter result = new StringWriter(s.length());
-            Reader in = null;
-            try {
-              in = new HTMLStripCharFilter(new StringReader(s.toString()));
+            try (Reader in = new HTMLStripCharFilter(new StringReader(s.toString()))) {
               in.transferTo(result);
               return result.toString();
             } catch (IOException e) {
               // we tried and failed
               return s;
-            } finally {
-              IOUtils.closeQuietly(in);
             }
           }
           return src;
diff --git a/solr/core/src/java/org/apache/solr/update/processor/RegexpBoostProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/RegexpBoostProcessor.java
index 46faeda1912..84d6de73d2b 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/RegexpBoostProcessor.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/RegexpBoostProcessor.java
@@ -26,7 +26,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.request.SolrQueryRequest;
@@ -124,9 +123,9 @@ public class RegexpBoostProcessor extends UpdateRequestProcessor {
   private List<BoostEntry> initBoostEntries(InputStream is) throws IOException {
     List<BoostEntry> newBoostEntries = new ArrayList<>();
 
-    BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
-    try {
-      String line = null;
+    try (BufferedReader reader =
+        new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+      String line;
       while ((line = reader.readLine()) != null) {
         // Remove comments
         line = line.replaceAll("\\s+#.*$", "");
@@ -149,11 +148,8 @@ public class RegexpBoostProcessor extends UpdateRequestProcessor {
               "Malformed config input line: {} (expected 2 fields, got {} fields).  Skipping entry.",
               line,
               fields.length);
-          continue;
         }
       }
-    } finally {
-      IOUtils.closeQuietly(reader);
     }
 
     return newBoostEntries;
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 48b1eb409c8..0f11ed44147 100755
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -3653,7 +3653,7 @@ public class SolrCLI implements CLIO {
     }
 
     protected void copyIfNeeded(File src, File dest) throws IOException {
-      if (!dest.isFile()) FileUtils.copyFile(src, dest);
+      if (!dest.isFile()) Files.copy(src.toPath(), dest.toPath());
 
       if (!dest.isFile())
         throw new IllegalStateException("Required file " + dest.getAbsolutePath() + " not found!");
diff --git a/solr/core/src/test/org/apache/solr/SolrTestCaseJ4Test.java b/solr/core/src/test/org/apache/solr/SolrTestCaseJ4Test.java
index 5779f265e61..976eea1f0db 100644
--- a/solr/core/src/test/org/apache/solr/SolrTestCaseJ4Test.java
+++ b/solr/core/src/test/org/apache/solr/SolrTestCaseJ4Test.java
@@ -17,6 +17,8 @@
 package org.apache.solr;
 
 import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.junit.AfterClass;
@@ -31,15 +33,14 @@ public class SolrTestCaseJ4Test extends SolrTestCaseJ4 {
     // configuration sets we can, so we don't copy that much junk around.
     String tmpSolrHome = createTempDir().toFile().getAbsolutePath();
 
-    File subHome = new File(new File(tmpSolrHome, "core0"), "conf");
-    assertTrue("Failed to make subdirectory ", subHome.mkdirs());
+    Path subHome = Path.of(tmpSolrHome, "core0", "conf");
+    Files.createDirectories(subHome);
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(subHome, "schema-tiny.xml"));
-    FileUtils.copyFile(
-        new File(top, "solrconfig-minimal.xml"), new File(subHome, "solrconfig-minimal.xml"));
-    FileUtils.copyFile(
-        new File(top, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(Path.of(top, "schema-tiny.xml"), subHome.resolve("schema-tiny.xml"));
+    Files.copy(Path.of(top, "solrconfig-minimal.xml"), subHome.resolve("solrconfig-minimal.xml"));
+    Files.copy(
+        Path.of(top, "solrconfig.snippet.randomindexconfig.xml"),
+        subHome.resolve("solrconfig.snippet.randomindexconfig.xml"));
 
     FileUtils.copyDirectory(new File(tmpSolrHome, "core0"), new File(tmpSolrHome, "core1"));
     // Core discovery will default to the name of the dir the core.properties file is in. So if
@@ -47,7 +48,7 @@ public class SolrTestCaseJ4Test extends SolrTestCaseJ4 {
     FileUtils.touch(new File(tmpSolrHome, "core0/core.properties"));
     FileUtils.touch(new File(tmpSolrHome, "core1/core.properties"));
 
-    FileUtils.copyFile(getFile("solr/solr.xml"), new File(tmpSolrHome, "solr.xml"));
+    Files.copy(getFile("solr/solr.xml").toPath(), Path.of(tmpSolrHome, "solr.xml"));
 
     initCore("solrconfig-minimal.xml", "schema-tiny.xml", tmpSolrHome, "core1");
   }
diff --git a/solr/core/src/test/org/apache/solr/TestSolrCoreProperties.java b/solr/core/src/test/org/apache/solr/TestSolrCoreProperties.java
index a5bdd915ce1..9f77a41a92a 100644
--- a/solr/core/src/test/org/apache/solr/TestSolrCoreProperties.java
+++ b/solr/core/src/test/org/apache/solr/TestSolrCoreProperties.java
@@ -16,15 +16,11 @@
  */
 package org.apache.solr;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Properties;
-import org.apache.commons.io.FileUtils;
-import org.apache.lucene.util.IOUtils;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
@@ -42,37 +38,35 @@ public class TestSolrCoreProperties extends SolrJettyTestBase {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
-    File homeDir = createTempDir().toFile();
+    Path homeDir = createTempDir();
 
-    File collDir = new File(homeDir, "collection1");
-    File dataDir = new File(collDir, "data");
-    File confDir = new File(collDir, "conf");
+    Path collDir = homeDir.resolve("collection1");
+    Path dataDir = collDir.resolve("data");
+    Path confDir = collDir.resolve("conf");
 
-    homeDir.mkdirs();
-    collDir.mkdirs();
-    dataDir.mkdirs();
-    confDir.mkdirs();
+    Files.createDirectories(homeDir);
+    Files.createDirectories(collDir);
+    Files.createDirectories(dataDir);
+    Files.createDirectories(confDir);
 
-    FileUtils.copyFile(
-        new File(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), new File(homeDir, "solr.xml"));
+    Files.copy(Path.of(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), homeDir.resolve("solr.xml"));
     String src_dir = TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(src_dir, "schema-tiny.xml"), new File(confDir, "schema.xml"));
-    FileUtils.copyFile(
-        new File(src_dir, "solrconfig-coreproperties.xml"), new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        new File(src_dir, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(confDir, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(Path.of(src_dir, "schema-tiny.xml"), confDir.resolve("schema.xml"));
+    Files.copy(
+        Path.of(src_dir, "solrconfig-coreproperties.xml"), confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        Path.of(src_dir, "solrconfig.snippet.randomindexconfig.xml"),
+        confDir.resolve("solrconfig.snippet.randomindexconfig.xml"));
 
     Properties p = new Properties();
     p.setProperty("foo.foo1", "f1");
     p.setProperty("foo.foo2", "f2");
-    Writer fos =
-        new OutputStreamWriter(
-            new FileOutputStream(new File(confDir, "solrcore.properties")), StandardCharsets.UTF_8);
-    p.store(fos, null);
-    IOUtils.close(fos);
+    try (Writer fos =
+        Files.newBufferedWriter(confDir.resolve("solrcore.properties"), StandardCharsets.UTF_8)) {
+      p.store(fos, null);
+    }
 
-    Files.createFile(collDir.toPath().resolve("core.properties"));
+    Files.createFile(collDir.resolve("core.properties"));
 
     Properties nodeProperties = new Properties();
     // this sets the property for jetty starting SolrDispatchFilter
@@ -80,7 +74,8 @@ public class TestSolrCoreProperties extends SolrJettyTestBase {
       nodeProperties.setProperty("solr.data.dir", createTempDir().toFile().getCanonicalPath());
     }
     jetty =
-        new JettySolrRunner(homeDir.getAbsolutePath(), nodeProperties, buildJettyConfig("/solr"));
+        new JettySolrRunner(
+            homeDir.toAbsolutePath().toString(), nodeProperties, buildJettyConfig("/solr"));
 
     jetty.start();
     port = jetty.getLocalPort();
diff --git a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
index f218823471c..a28fc90ece1 100644
--- a/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
+++ b/solr/core/src/test/org/apache/solr/TestTolerantSearch.java
@@ -19,6 +19,9 @@ package org.apache.solr;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
@@ -43,13 +46,15 @@ public class TestTolerantSearch extends SolrJettyTestBase {
   private static String shard2;
 
   private static File createSolrHome() throws Exception {
-    File workDir = createTempDir().toFile();
-    setupJettyTestHome(workDir, "collection1");
-    FileUtils.copyFile(
-        new File(SolrTestCaseJ4.TEST_HOME() + "/collection1/conf/solrconfig-tolerant-search.xml"),
-        new File(workDir, "/collection1/conf/solrconfig.xml"));
-    FileUtils.copyDirectory(new File(workDir, "collection1"), new File(workDir, "collection2"));
-    return workDir;
+    Path workDir = createTempDir();
+    setupJettyTestHome(workDir.toFile(), "collection1");
+    Files.copy(
+        Path.of(SolrTestCaseJ4.TEST_HOME() + "/collection1/conf/solrconfig-tolerant-search.xml"),
+        workDir.resolve("collection1").resolve("conf").resolve("solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
+    FileUtils.copyDirectory(
+        workDir.resolve("collection1").toFile(), workDir.resolve("collection2").toFile());
+    return workDir.toFile();
   }
 
   @BeforeClass
diff --git a/solr/core/src/test/org/apache/solr/cloud/SolrXmlInZkTest.java b/solr/core/src/test/org/apache/solr/cloud/SolrXmlInZkTest.java
index a9473e1249d..fec4dfab74b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/SolrXmlInZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/SolrXmlInZkTest.java
@@ -19,10 +19,10 @@ package org.apache.solr.cloud;
 import java.io.File;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.SolrZkClient;
@@ -47,9 +47,8 @@ public class SolrXmlInZkTest extends SolrTestCaseJ4 {
     Path solrHome = tmpDir.resolve("home");
     copyMinConf(new File(solrHome.toFile(), "myCollect"));
     if (leaveOnLocal) {
-      FileUtils.copyFile(
-          new File(SolrTestCaseJ4.TEST_HOME(), "solr-stress-new.xml"),
-          new File(solrHome.toFile(), "solr.xml"));
+      Files.copy(
+          Path.of(SolrTestCaseJ4.TEST_HOME(), "solr-stress-new.xml"), solrHome.resolve("solr.xml"));
     }
 
     ignoreException("No UpdateLog found - cannot sync");
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
index 0038351f706..c21777686a9 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudRecovery.java
@@ -21,15 +21,15 @@ import com.codahale.metrics.Counter;
 import com.codahale.metrics.Metric;
 import com.codahale.metrics.Timer;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.response.QueryResponse;
@@ -192,11 +192,9 @@ public class TestCloudRecovery extends SolrCloudTestCase {
         String[] tLogFiles = tlogFolder.list();
         Arrays.sort(tLogFiles);
         String lastTLogFile = tlogFolder.getAbsolutePath() + "/" + tLogFiles[tLogFiles.length - 1];
-        try (FileInputStream inputStream = new FileInputStream(lastTLogFile)) {
-          byte[] tlogBytes = IOUtils.toByteArray(inputStream);
-          contentFiles.put(lastTLogFile, tlogBytes);
-          logHeaderSize = Math.min(tlogBytes.length, logHeaderSize);
-        }
+        byte[] tlogBytes = Files.readAllBytes(Path.of(lastTLogFile));
+        contentFiles.put(lastTLogFile, tlogBytes);
+        logHeaderSize = Math.min(tlogBytes.length, logHeaderSize);
       }
     }
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
index 0a26e358cbe..efc92fec914 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
@@ -360,12 +360,9 @@ public class TestConfigSetsAPI extends SolrCloudTestCase {
     }
 
     if (oldPropsData != null) {
-      InputStreamReader reader =
-          new InputStreamReader(new ByteArrayInputStream(oldPropsData), UTF_8);
-      try {
+      try (InputStreamReader reader =
+          new InputStreamReader(new ByteArrayInputStream(oldPropsData), UTF_8)) {
         return ConfigSetProperties.readFromInputStream(reader);
-      } finally {
-        reader.close();
       }
     }
     return null;
diff --git a/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java b/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java
index bcacb569a4f..3a84f483ff7 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ZkCLITest.java
@@ -18,18 +18,16 @@ package org.apache.solr.cloud;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
 import java.io.PrintStream;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.filefilter.RegexFileFilter;
 import org.apache.commons.io.filefilter.TrueFileFilter;
 import org.apache.commons.lang3.StringUtils;
@@ -214,14 +212,8 @@ public class ZkCLITest extends SolrTestCaseJ4 {
 
     String fromZk =
         new String(zkClient.getData("/solr.xml", null, null, true), StandardCharsets.UTF_8);
-    File locFile = new File(SOLR_HOME + File.separator + "solr-stress-new.xml");
-    InputStream is = new FileInputStream(locFile);
-    String fromLoc;
-    try {
-      fromLoc = new String(IOUtils.toByteArray(is), StandardCharsets.UTF_8);
-    } finally {
-      IOUtils.closeQuietly(is);
-    }
+    Path locFile = Path.of(SOLR_HOME, "solr-stress-new.xml");
+    String fromLoc = Files.readString(locFile);
     assertEquals("Should get back what we put in ZK", fromZk, fromLoc);
   }
 
@@ -243,16 +235,8 @@ public class ZkCLITest extends SolrTestCaseJ4 {
     ZkCLI.main(args);
 
     byte[] fromZk = zkClient.getZooKeeper().getData("/state.json", null, null);
-    File locFile = new File(SOLR_HOME + File.separator + "solr-stress-new.xml");
-    InputStream is = new FileInputStream(locFile);
-    byte[] fromLoc;
-    try {
-      fromLoc = IOUtils.toByteArray(is);
-      ZLibCompressor zLibCompressor = new ZLibCompressor();
-      fromLoc = zLibCompressor.compressBytes(fromLoc);
-    } finally {
-      IOUtils.closeQuietly(is);
-    }
+    Path locFile = Path.of(SOLR_HOME, "solr-stress-new.xml");
+    byte[] fromLoc = new ZLibCompressor().compressBytes(Files.readAllBytes(locFile));
     assertArrayEquals("Should get back what we put in ZK", fromLoc, fromZk);
   }
 
@@ -268,10 +252,10 @@ public class ZkCLITest extends SolrTestCaseJ4 {
           "/solr.xml",
           SOLR_HOME + File.separator + "not-there.xml"
         };
-    FileNotFoundException e = expectThrows(FileNotFoundException.class, () -> ZkCLI.main(args));
+    NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> ZkCLI.main(args));
     assertTrue(
         "Didn't find expected error message containing 'not-there.xml' in " + e.getMessage(),
-        e.getMessage().indexOf("not-there.xml") != -1);
+        e.getMessage().contains("not-there.xml"));
   }
 
   @Test
@@ -280,12 +264,12 @@ public class ZkCLITest extends SolrTestCaseJ4 {
     String[] args = new String[] {"-zkhost", zkServer.getZkAddress(), "-cmd", "list"};
 
     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-    final PrintStream myOut = new PrintStream(byteStream, false, StandardCharsets.UTF_8.name());
+    final PrintStream myOut = new PrintStream(byteStream, false, StandardCharsets.UTF_8);
     ZkCLI.setStdout(myOut);
 
     ZkCLI.main(args);
 
-    final String standardOutput = byteStream.toString(StandardCharsets.UTF_8.name());
+    final String standardOutput = byteStream.toString(StandardCharsets.UTF_8);
     String separator = System.lineSeparator();
     assertEquals("/ (1)" + separator + " /test (0)" + separator + separator, standardOutput);
   }
@@ -296,12 +280,12 @@ public class ZkCLITest extends SolrTestCaseJ4 {
     String[] args = new String[] {"-zkhost", zkServer.getZkAddress(), "-cmd", "ls", "/test"};
 
     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
-    final PrintStream myOut = new PrintStream(byteStream, false, StandardCharsets.UTF_8.name());
+    final PrintStream myOut = new PrintStream(byteStream, false, StandardCharsets.UTF_8);
     ZkCLI.setStdout(myOut);
 
     ZkCLI.main(args);
 
-    final String standardOutput = byteStream.toString(StandardCharsets.UTF_8.name());
+    final String standardOutput = byteStream.toString(StandardCharsets.UTF_8);
     String separator = System.lineSeparator();
     assertEquals(
         "/test (1)" + separator + " /test/path (0)" + separator + separator, standardOutput);
diff --git a/solr/core/src/test/org/apache/solr/core/TestConfigSets.java b/solr/core/src/test/org/apache/solr/core/TestConfigSets.java
index 458e0e8eb1c..29cc1f16a17 100644
--- a/solr/core/src/test/org/apache/solr/core/TestConfigSets.java
+++ b/solr/core/src/test/org/apache/solr/core/TestConfigSets.java
@@ -22,12 +22,13 @@ import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.StringContains.containsString;
 
 import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.Map;
-import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.file.PathUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.hamcrest.MatcherAssert;
 import org.junit.Rule;
@@ -110,11 +111,11 @@ public class TestConfigSets extends SolrTestCaseJ4 {
   @Test
   public void testConfigSetOnCoreReload() throws IOException {
     Path testDirectory = createTempDir("core-reload");
-    File configSetsDir = new File(testDirectory.toFile(), "configsets");
+    Path configSetsDir = testDirectory.resolve("configsets");
 
-    FileUtils.copyDirectory(getFile("solr/configsets"), configSetsDir);
+    PathUtils.copyDirectory(getFile("solr/configsets").toPath(), configSetsDir);
 
-    String csd = configSetsDir.getAbsolutePath();
+    String csd = configSetsDir.toAbsolutePath().toString();
     System.setProperty("configsets", csd);
 
     CoreContainer container = new CoreContainer(SolrXmlConfig.fromString(testDirectory, solrxml));
@@ -128,9 +129,10 @@ public class TestConfigSets extends SolrTestCaseJ4 {
         is(nullValue()));
 
     // Now copy in a config with a /dump handler and reload
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig-withgethandler.xml"),
-        new File(new File(configSetsDir, "configset-2/conf"), "solrconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig-withgethandler.xml").toPath(),
+        configSetsDir.resolve("configset-2/conf").resolve("solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
     container.reload("core1");
 
     core = container.getCore("core1");
diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
index 29f4864685f..acff002d9dd 100644
--- a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
+++ b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
@@ -26,9 +26,11 @@ import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import com.google.common.base.Throwables;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -38,8 +40,6 @@ import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.regex.Pattern;
 import org.apache.commons.exec.OS;
-import org.apache.commons.io.FileUtils;
-import org.apache.lucene.util.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.handler.admin.CollectionsHandler;
@@ -927,12 +927,16 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
 
     // -----
     // "fix" the bad collection
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig-defaults.xml"),
-        FileUtils.getFile(cc.getSolrHome(), "col_bad", "conf", "solrconfig.xml"));
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/schema-minimal.xml"),
-        FileUtils.getFile(cc.getSolrHome(), "col_bad", "conf", "schema.xml"));
+    Path confDir = Path.of(cc.getSolrHome(), "col_bad", "conf");
+    Files.createDirectories(confDir);
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig-defaults.xml").toPath(),
+        confDir.resolve("solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
+    Files.copy(
+        getFile("solr/collection1/conf/schema-minimal.xml").toPath(),
+        confDir.resolve("schema.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
     cc.create("col_bad", Map.of());
 
     // check that we have the cores we expect
@@ -998,10 +1002,10 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
 
     final long col_bad_old_start = getCoreStartTime(cc, "col_bad");
 
-    FileUtils.write(
-        FileUtils.getFile(cc.getSolrHome(), "col_bad", "conf", "solrconfig.xml"),
+    Files.writeString(
+        Path.of(cc.getSolrHome(), "col_bad", "conf", "solrconfig.xml"),
         "This is giberish, not valid XML <",
-        IOUtils.UTF_8);
+        StandardCharsets.UTF_8);
 
     ignoreException(Pattern.quote("SAX"));
     thrown =
@@ -1046,9 +1050,10 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
 
     // ----
     // fix col_bad's config (again) and RELOAD to fix failure
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig-defaults.xml"),
-        FileUtils.getFile(cc.getSolrHome(), "col_bad", "conf", "solrconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig-defaults.xml").toPath(),
+        confDir.resolve("solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
     cc.reload("col_bad");
 
     assertTrue(
diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java b/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
index 7840646becf..0bc3e0bbdf7 100644
--- a/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
+++ b/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
@@ -24,9 +24,7 @@ import static org.hamcrest.core.StringContains.containsString;
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
@@ -93,14 +91,13 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
   }
 
   private void addCoreWithProps(Properties stockProps, File propFile) throws Exception {
-    if (!propFile.getParentFile().exists()) propFile.getParentFile().mkdirs();
-    Writer out = new OutputStreamWriter(new FileOutputStream(propFile), StandardCharsets.UTF_8);
-    try {
+    if (!propFile.getParentFile().exists()) {
+      propFile.getParentFile().mkdirs();
+    }
+    try (Writer out = Files.newBufferedWriter(propFile.toPath(), StandardCharsets.UTF_8)) {
       stockProps.store(out, null);
-    } finally {
-      out.close();
     }
-    addConfFiles(new File(propFile.getParent(), "conf"));
+    addConfFiles(propFile.toPath().getParent().resolve("conf"));
   }
 
   private void addCoreWithProps(String name, Properties stockProps) throws Exception {
@@ -113,15 +110,14 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
     addCoreWithProps(stockProps, propFile);
   }
 
-  private void addConfFiles(File confDir) throws Exception {
+  private void addConfFiles(Path confDir) throws Exception {
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    assertTrue("Failed to mkdirs for " + confDir.getAbsolutePath(), confDir.mkdirs());
-    FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(confDir, "schema-tiny.xml"));
-    FileUtils.copyFile(
-        new File(top, "solrconfig-minimal.xml"), new File(confDir, "solrconfig-minimal.xml"));
-    FileUtils.copyFile(
-        new File(top, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(confDir, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.createDirectories(confDir);
+    Files.copy(Path.of(top, "schema-tiny.xml"), confDir.resolve("schema-tiny.xml"));
+    Files.copy(Path.of(top, "solrconfig-minimal.xml"), confDir.resolve("solrconfig-minimal.xml"));
+    Files.copy(
+        Path.of(top, "solrconfig.snippet.randomindexconfig.xml"),
+        confDir.resolve("solrconfig.snippet.randomindexconfig.xml"));
   }
 
   private CoreContainer init() {
diff --git a/solr/core/src/test/org/apache/solr/core/TestLazyCores.java b/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
index cc76cefd791..62e4fcc363e 100644
--- a/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
+++ b/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
@@ -19,6 +19,9 @@ package org.apache.solr.core;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -720,13 +723,12 @@ public class TestLazyCores extends SolrTestCaseJ4 {
 
     // Collect the files that we'll write to the config directories.
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    String min_schema =
-        FileUtils.readFileToString(new File(top, "schema-tiny.xml"), StandardCharsets.UTF_8);
+    String min_schema = Files.readString(Path.of(top, "schema-tiny.xml"), StandardCharsets.UTF_8);
     String min_config =
-        FileUtils.readFileToString(new File(top, "solrconfig-minimal.xml"), StandardCharsets.UTF_8);
+        Files.readString(Path.of(top, "solrconfig-minimal.xml"), StandardCharsets.UTF_8);
     String rand_snip =
-        FileUtils.readFileToString(
-            new File(top, "solrconfig.snippet.randomindexconfig.xml"), StandardCharsets.UTF_8);
+        Files.readString(
+            Path.of(top, "solrconfig.snippet.randomindexconfig.xml"), StandardCharsets.UTF_8);
 
     // Now purposely mess up the config files, introducing stupid syntax errors.
     String bad_config = min_config.replace("<requestHandler", "<reqsthalr");
@@ -751,10 +753,11 @@ public class TestLazyCores extends SolrTestCaseJ4 {
   // We want to see that the core "heals itself" if an un-corrupted file is written to the
   // directory.
   private void copyGoodConf(String coreName, String srcName, String dstName) throws IOException {
-    File coreRoot = new File(solrHomeDirectory, coreName);
-    File subHome = new File(coreRoot, "conf");
+    Path coreRoot = solrHomeDirectory.toPath().resolve(coreName);
+    Path subHome = coreRoot.resolve("conf");
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(top, srcName), new File(subHome, dstName));
+    Files.copy(
+        Path.of(top, srcName), subHome.resolve(dstName), StandardCopyOption.REPLACE_EXISTING);
   }
 
   // If ok==true, we shouldn't be seeing any failure cases.
diff --git a/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java
index 111c7de0d70..859a07e3e15 100644
--- a/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java
@@ -18,6 +18,8 @@ package org.apache.solr.handler;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.util.List;
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
@@ -102,7 +104,7 @@ public class PingRequestHandlerTest extends SolrTestCaseJ4 {
     makeRequest(handler, req("action", "enable"));
 
     assertTrue(healthcheckFile.exists());
-    assertNotNull(FileUtils.readFileToString(healthcheckFile, "UTF-8"));
+    assertNotNull(Files.readString(healthcheckFile.toPath(), StandardCharsets.UTF_8));
 
     // now verify that the handler response with success
 
diff --git a/solr/core/src/test/org/apache/solr/handler/ReplicationTestHelper.java b/solr/core/src/test/org/apache/solr/handler/ReplicationTestHelper.java
index ca0a4409a1d..7c1eb858244 100644
--- a/solr/core/src/test/org/apache/solr/handler/ReplicationTestHelper.java
+++ b/solr/core/src/test/org/apache/solr/handler/ReplicationTestHelper.java
@@ -18,16 +18,13 @@ package org.apache.solr.handler;
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.lang.invoke.MethodHandles;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Properties;
 import org.apache.lucene.tests.util.LuceneTestCase;
@@ -83,11 +80,8 @@ public final class ReplicationTestHelper {
    */
   private static void copyFile(File src, File dst, Integer port, boolean internalCompression)
       throws IOException {
-    try (BufferedReader in =
-            new BufferedReader(
-                new InputStreamReader(new FileInputStream(src), StandardCharsets.UTF_8));
-        Writer out = new OutputStreamWriter(new FileOutputStream(dst), StandardCharsets.UTF_8)) {
-
+    try (BufferedReader in = Files.newBufferedReader(src.toPath(), StandardCharsets.UTF_8);
+        Writer out = Files.newBufferedWriter(dst.toPath(), StandardCharsets.UTF_8)) {
       for (String line = in.readLine(); null != line; line = in.readLine()) {
         if (null != port) {
           line = line.replace("TEST_PORT", port.toString());
diff --git a/solr/core/src/test/org/apache/solr/handler/TestCSVLoader.java b/solr/core/src/test/org/apache/solr/handler/TestCSVLoader.java
index c24a17114c3..bbff8694af3 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestCSVLoader.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestCSVLoader.java
@@ -17,11 +17,10 @@
 package org.apache.solr.handler;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.solr.SolrTestCaseJ4;
@@ -69,13 +68,8 @@ public class TestCSVLoader extends SolrTestCaseJ4 {
     }
   }
 
-  void makeFile(String contents) {
-    try (Writer out =
-        new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8)) {
-      out.write(contents);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
+  void makeFile(String contents) throws IOException {
+    Files.writeString(Path.of(filename), contents, StandardCharsets.UTF_8);
   }
 
   void cleanup() {
diff --git a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
index 1440ee486e3..49c3f925bf8 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestContainerPlugin.java
@@ -32,7 +32,6 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.Phaser;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.util.ResourceLoader;
 import org.apache.lucene.util.ResourceLoaderAware;
 import org.apache.solr.api.Command;
@@ -441,10 +440,9 @@ public class TestContainerPlugin extends SolrCloudTestCase {
     @Override
     public void inform(ResourceLoader loader) {
       this.resourceLoader = (SolrResourceLoader) loader;
-      try {
-        InputStream is = resourceLoader.openResource("org/apache/solr/handler/MyPlugin.class");
+      try (InputStream is = resourceLoader.openResource("org/apache/solr/handler/MyPlugin.class")) {
         byte[] buf = new byte[1024 * 5];
-        int sz = IOUtils.read(is, buf);
+        int sz = is.read(buf);
         classData = ByteBuffer.wrap(buf, 0, sz);
       } catch (IOException e) {
         // do not do anything
diff --git a/solr/core/src/test/org/apache/solr/handler/TestReplicationHandlerBackup.java b/solr/core/src/test/org/apache/solr/handler/TestReplicationHandlerBackup.java
index b378834c1ba..2af23d1a530 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestReplicationHandlerBackup.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestReplicationHandlerBackup.java
@@ -29,7 +29,6 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Properties;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.search.IndexSearcher;
@@ -258,13 +257,9 @@ public class TestReplicationHandlerBackup extends SolrJettyTestBase {
             + "?wt=xml&command="
             + cmd
             + params;
-    InputStream stream = null;
-    try {
-      URL url = new URL(leaderUrl);
-      stream = url.openStream();
-      stream.close();
-    } finally {
-      IOUtils.closeQuietly(stream);
+    URL url = new URL(leaderUrl);
+    try (InputStream stream = url.openStream()) {
+      assert stream != null;
     }
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/handler/V2StandaloneTest.java b/solr/core/src/test/org/apache/solr/handler/V2StandaloneTest.java
index 0d1251d3265..a5672d42b3d 100644
--- a/solr/core/src/test/org/apache/solr/handler/V2StandaloneTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/V2StandaloneTest.java
@@ -17,8 +17,9 @@
 
 package org.apache.solr.handler;
 
-import java.io.File;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.apache.commons.io.file.PathUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.request.V2Request;
@@ -30,13 +31,13 @@ public class V2StandaloneTest extends SolrTestCaseJ4 {
 
   @Test
   public void testWelcomeMessage() throws Exception {
-    File solrHomeTmp = createTempDir().toFile().getAbsoluteFile();
-    FileUtils.copyDirectory(
-        new File(TEST_HOME(), "configsets/minimal/conf"), new File(solrHomeTmp, "/conf"));
-    FileUtils.copyFile(new File(TEST_HOME(), "solr.xml"), new File(solrHomeTmp, "solr.xml"));
+    Path solrHomeTmp = createTempDir().toAbsolutePath();
+    PathUtils.copyDirectory(
+        Path.of(TEST_HOME(), "configsets/minimal/conf"), solrHomeTmp.resolve("conf"));
+    Files.copy(Path.of(TEST_HOME(), "solr.xml"), solrHomeTmp.resolve("solr.xml"));
 
     JettySolrRunner jetty =
-        new JettySolrRunner(solrHomeTmp.getAbsolutePath(), buildJettyConfig("/solr"));
+        new JettySolrRunner(solrHomeTmp.toAbsolutePath().toString(), buildJettyConfig("/solr"));
     jetty.start();
 
     try (SolrClient client = getHttpSolrClient(buildUrl(jetty.getLocalPort(), "/solr/"))) {
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminCreateDiscoverTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminCreateDiscoverTest.java
index 8bcfb199c6b..81a16ab858f 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminCreateDiscoverTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminCreateDiscoverTest.java
@@ -17,12 +17,12 @@
 package org.apache.solr.handler.admin;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.Reader;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Properties;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.CoreAdminParams;
@@ -61,19 +61,18 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
   }
 
   private static void setupCore(String coreName) throws IOException {
-    File instDir = new File(solrHomeDirectory, coreName);
-    File subHome = new File(instDir, "conf");
-    assertTrue("Failed to make subdirectory ", subHome.mkdirs());
+    Path instDir = solrHomeDirectory.toPath().resolve(coreName);
+    Path subHome = instDir.resolve("conf");
+    Files.createDirectories(subHome);
 
     // Be sure we pick up sysvars when we create this
     String srcDir = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(srcDir, "schema-tiny.xml"), new File(subHome, "schema_ren.xml"));
-    FileUtils.copyFile(
-        new File(srcDir, "solrconfig-minimal.xml"), new File(subHome, "solrconfig_ren.xml"));
+    Files.copy(Path.of(srcDir, "schema-tiny.xml"), subHome.resolve("schema_ren.xml"));
+    Files.copy(Path.of(srcDir, "solrconfig-minimal.xml"), subHome.resolve("solrconfig_ren.xml"));
 
-    FileUtils.copyFile(
-        new File(srcDir, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(
+        Path.of(srcDir, "solrconfig.snippet.randomindexconfig.xml"),
+        subHome.resolve("solrconfig.snippet.randomindexconfig.xml"));
   }
 
   @Test
@@ -112,32 +111,32 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
     // verify props are in persisted file
 
     Properties props = new Properties();
-    File propFile =
-        new File(solrHomeDirectory, coreSysProps + "/" + CorePropertiesLocator.PROPERTIES_FILENAME);
-    FileInputStream is = new FileInputStream(propFile);
-    try {
-      props.load(new InputStreamReader(is, StandardCharsets.UTF_8));
-    } finally {
-      org.apache.commons.io.IOUtils.closeQuietly(is);
+    Path propFile =
+        solrHomeDirectory
+            .toPath()
+            .resolve(coreSysProps)
+            .resolve(CorePropertiesLocator.PROPERTIES_FILENAME);
+    try (Reader r = Files.newBufferedReader(propFile, StandardCharsets.UTF_8)) {
+      props.load(r);
     }
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.NAME),
         coreSysProps);
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.CONFIG),
         "${CONFIG_TEST}");
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.SCHEMA),
         "${SCHEMA_TEST}");
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.DATA_DIR),
         "${DATA_TEST}");
 
@@ -290,32 +289,32 @@ public class CoreAdminCreateDiscoverTest extends SolrTestCaseJ4 {
 
     // verify props are in persisted file
     Properties props = new Properties();
-    File propFile =
-        new File(solrHomeDirectory, coreNormal + "/" + CorePropertiesLocator.PROPERTIES_FILENAME);
-    FileInputStream is = new FileInputStream(propFile);
-    try {
-      props.load(new InputStreamReader(is, StandardCharsets.UTF_8));
-    } finally {
-      org.apache.commons.io.IOUtils.closeQuietly(is);
+    Path propFile =
+        solrHomeDirectory
+            .toPath()
+            .resolve(coreNormal)
+            .resolve(CorePropertiesLocator.PROPERTIES_FILENAME);
+    try (Reader r = Files.newBufferedReader(propFile, StandardCharsets.UTF_8)) {
+      props.load(r);
     }
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.NAME),
         coreNormal);
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.CONFIG),
         "solrconfig_ren.xml");
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.SCHEMA),
         "schema_ren.xml");
 
     assertEquals(
-        "Unexpected value preserved in properties file " + propFile.getAbsolutePath(),
+        "Unexpected value preserved in properties file " + propFile.toAbsolutePath(),
         props.getProperty(CoreAdminParams.DATA_DIR),
         data.getAbsolutePath());
 
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
index aa44bc0f9dc..0c6749e383f 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreAdminHandlerTest.java
@@ -16,16 +16,15 @@
  */
 package org.apache.solr.handler.admin;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
+import java.io.Reader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
 import java.util.Map;
 import java.util.Properties;
-import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.file.PathUtils;
 import org.apache.lucene.util.Constants;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
@@ -61,34 +60,33 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
   public void testCreateWithSysVars() throws Exception {
     useFactory(null); // I require FS-based indexes for this test.
 
-    final File workDir = createTempDir(getCoreName()).toFile();
+    final Path workDir = createTempDir(getCoreName());
 
     String coreName = "with_sys_vars";
-    File instDir = new File(workDir, coreName);
-    File subHome = new File(instDir, "conf");
-    assertTrue("Failed to make subdirectory ", subHome.mkdirs());
+    Path instDir = workDir.resolve(coreName);
+    Path subHome = instDir.resolve("conf");
+    Files.createDirectories(subHome);
 
     // Be sure we pick up sysvars when we create this
     String srcDir = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(srcDir, "schema-tiny.xml"), new File(subHome, "schema_ren.xml"));
-    FileUtils.copyFile(
-        new File(srcDir, "solrconfig-minimal.xml"), new File(subHome, "solrconfig_ren.xml"));
-    FileUtils.copyFile(
-        new File(srcDir, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(Path.of(srcDir, "schema-tiny.xml"), subHome.resolve("schema_ren.xml"));
+    Files.copy(Path.of(srcDir, "solrconfig-minimal.xml"), subHome.resolve("solrconfig_ren.xml"));
+    Files.copy(
+        Path.of(srcDir, "solrconfig.snippet.randomindexconfig.xml"),
+        subHome.resolve("solrconfig.snippet.randomindexconfig.xml"));
 
     final CoreContainer cores = h.getCoreContainer();
-    cores.getAllowPaths().add(workDir.toPath());
+    cores.getAllowPaths().add(workDir);
 
     final CoreAdminHandler admin = new CoreAdminHandler(cores);
 
     // create a new core (using CoreAdminHandler) w/ properties
-    System.setProperty("INSTDIR_TEST", instDir.getAbsolutePath());
+    System.setProperty("INSTDIR_TEST", instDir.toAbsolutePath().toString());
     System.setProperty("CONFIG_TEST", "solrconfig_ren.xml");
     System.setProperty("SCHEMA_TEST", "schema_ren.xml");
 
-    File dataDir = new File(workDir.getAbsolutePath(), "data_diff");
-    System.setProperty("DATA_TEST", dataDir.getAbsolutePath());
+    Path dataDir = workDir.resolve("data_diff");
+    System.setProperty("DATA_TEST", dataDir.toAbsolutePath().toString());
 
     SolrQueryResponse resp = new SolrQueryResponse();
     admin.handleRequestBody(
@@ -112,26 +110,26 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
     // see SOLR-4982.
 
     // Should NOT be a datadir named ${DATA_TEST} (literal). This is the bug after all
-    File badDir = new File(instDir, "${DATA_TEST}");
+    Path badDir = instDir.resolve("${DATA_TEST}");
     assertFalse(
-        "Should have substituted the sys var, found file " + badDir.getAbsolutePath(),
-        badDir.exists());
+        "Should have substituted the sys var, found file " + badDir.toAbsolutePath(),
+        Files.exists(badDir));
 
     // For the other 3 vars, we couldn't get past creating the core fi dereferencing didn't work
     // correctly.
 
     // Should have segments in the directory pointed to by the ${DATA_TEST}.
-    File test = new File(dataDir, "index");
-    assertTrue("Should have found index dir at " + test.getAbsolutePath(), test.exists());
+    Path test = dataDir.resolve("index");
+    assertTrue("Should have found index dir at " + test.toAbsolutePath(), Files.exists(test));
     admin.close();
   }
 
   @Test
   public void testCoreAdminHandler() throws Exception {
-    final File workDir = createTempDir().toFile();
+    final Path workDir = createTempDir();
 
     final CoreContainer cores = h.getCoreContainer();
-    cores.getAllowPaths().add(workDir.toPath());
+    cores.getAllowPaths().add(workDir);
 
     final CoreAdminHandler admin = new CoreAdminHandler(cores);
 
@@ -142,8 +140,8 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
     }
 
     assertTrue("instDir doesn't exist: " + instDir, Files.exists(instDir));
-    final File instPropFile = new File(workDir, "instProp");
-    FileUtils.copyDirectory(instDir.toFile(), instPropFile);
+    final Path instProp = workDir.resolve("instProp");
+    PathUtils.copyDirectory(instDir, instProp);
 
     SolrQueryResponse resp = new SolrQueryResponse();
     // Sneaking in a test for using a bad core name
@@ -156,7 +154,7 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
                       CoreAdminParams.ACTION,
                       CoreAdminParams.CoreAdminAction.CREATE.toString(),
                       CoreAdminParams.INSTANCE_DIR,
-                      instPropFile.getAbsolutePath(),
+                      instProp.toAbsolutePath().toString(),
                       CoreAdminParams.NAME,
                       "ugly$core=name"),
                   new SolrQueryResponse());
@@ -173,7 +171,7 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
             CoreAdminParams.ACTION,
             CoreAdminParams.CoreAdminAction.CREATE.toString(),
             CoreAdminParams.INSTANCE_DIR,
-            instPropFile.getAbsolutePath(),
+            instProp.toAbsolutePath().toString(),
             CoreAdminParams.NAME,
             "props",
             CoreAdminParams.PROPERTY_PREFIX + "hoss",
@@ -289,19 +287,20 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
 
   @Test
   public void testDeleteInstanceDir() throws Exception {
-    File solrHomeDirectory = createTempDir("solr-home").toFile();
-    copySolrHomeToTemp(solrHomeDirectory, "corex");
-    File corex = new File(solrHomeDirectory, "corex");
-    FileUtils.write(new File(corex, "core.properties"), "", StandardCharsets.UTF_8);
+    Path solrHomeDirectory = createTempDir("solr-home");
+    copySolrHomeToTemp(solrHomeDirectory.toFile(), "corex");
+    Path corex = solrHomeDirectory.resolve("corex");
+    Files.writeString(corex.resolve("core.properties"), "", StandardCharsets.UTF_8);
 
-    copySolrHomeToTemp(solrHomeDirectory, "corerename");
+    copySolrHomeToTemp(solrHomeDirectory.toFile(), "corerename");
 
-    File coreRename = new File(solrHomeDirectory, "corerename");
-    File renamePropFile = new File(coreRename, "core.properties");
-    FileUtils.write(renamePropFile, "", StandardCharsets.UTF_8);
+    Path coreRename = solrHomeDirectory.resolve("corerename");
+    Path renamePropFile = coreRename.resolve("core.properties");
+    Files.writeString(renamePropFile, "", StandardCharsets.UTF_8);
 
     JettySolrRunner runner =
-        new JettySolrRunner(solrHomeDirectory.getAbsolutePath(), buildJettyConfig("/solr"));
+        new JettySolrRunner(
+            solrHomeDirectory.toAbsolutePath().toString(), buildJettyConfig("/solr"));
     runner.start();
 
     try (SolrClient client =
@@ -337,8 +336,7 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
             DEFAULT_CONNECTION_TIMEOUT)) {
       CoreAdminRequest.renameCore("corerename", "brand_new_core_name", client);
       Properties props = new Properties();
-      try (InputStreamReader is =
-          new InputStreamReader(new FileInputStream(renamePropFile), StandardCharsets.UTF_8)) {
+      try (Reader is = Files.newBufferedReader(renamePropFile, StandardCharsets.UTF_8)) {
         props.load(is);
       }
       assertEquals(
@@ -360,21 +358,22 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
 
     assertFalse(
         "Instance directory exists after core unload with deleteInstanceDir=true : " + corex,
-        corex.exists());
+        Files.exists(corex));
 
     assertFalse(
         "Instance directory exists after core unload with deleteInstanceDir=true : " + coreRename,
-        coreRename.exists());
+        Files.exists(coreRename));
   }
 
   @Test
   public void testUnloadForever() throws Exception {
-    File solrHomeDirectory = createTempDir("solr-home").toFile();
-    copySolrHomeToTemp(solrHomeDirectory, "corex");
-    File corex = new File(solrHomeDirectory, "corex");
-    FileUtils.write(new File(corex, "core.properties"), "", StandardCharsets.UTF_8);
+    Path solrHomeDirectory = createTempDir("solr-home");
+    copySolrHomeToTemp(solrHomeDirectory.toFile(), "corex");
+    Path corex = solrHomeDirectory.resolve("corex");
+    Files.writeString(corex.resolve("core.properties"), "", StandardCharsets.UTF_8);
     JettySolrRunner runner =
-        new JettySolrRunner(solrHomeDirectory.getAbsolutePath(), buildJettyConfig("/solr"));
+        new JettySolrRunner(
+            solrHomeDirectory.toAbsolutePath().toString(), buildJettyConfig("/solr"));
     runner.start();
 
     try (SolrClient client =
@@ -430,12 +429,13 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
     assumeFalse(
         "Ignore test on windows because it does not delete data directory immediately after unload",
         Constants.WINDOWS);
-    File solrHomeDirectory = createTempDir("solr-home").toFile();
-    copySolrHomeToTemp(solrHomeDirectory, "corex");
-    File corex = new File(solrHomeDirectory, "corex");
-    FileUtils.write(new File(corex, "core.properties"), "", StandardCharsets.UTF_8);
+    Path solrHomeDirectory = createTempDir("solr-home");
+    copySolrHomeToTemp(solrHomeDirectory.toFile(), "corex");
+    Path corex = solrHomeDirectory.resolve("corex");
+    Files.writeString(corex.resolve("core.properties"), "", StandardCharsets.UTF_8);
     JettySolrRunner runner =
-        new JettySolrRunner(solrHomeDirectory.getAbsolutePath(), buildJettyConfig("/solr"));
+        new JettySolrRunner(
+            solrHomeDirectory.toAbsolutePath().toString(), buildJettyConfig("/solr"));
     runner.start();
 
     try (SolrClient client =
@@ -457,10 +457,12 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
       assertTrue(Files.exists(dataDir));
     }
 
-    File subHome = new File(solrHomeDirectory, "corex" + File.separator + "conf");
+    Path subHome = solrHomeDirectory.resolve("corex").resolve("conf");
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(
-        new File(top, "bad-error-solrconfig.xml"), new File(subHome, "solrconfig.xml"));
+    Files.copy(
+        Path.of(top, "bad-error-solrconfig.xml"),
+        subHome.resolve("solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
 
     try (SolrClient client =
         getHttpSolrClient(
@@ -472,8 +474,8 @@ public class CoreAdminHandlerTest extends SolrTestCaseJ4 {
 
       CoreAdminRequest.Unload req = new CoreAdminRequest.Unload(false);
       req.setDeleteDataDir(true);
-      req.setDeleteInstanceDir(
-          false); // important because the data directory is inside the instance directory
+      // important because the data directory is inside the instance directory
+      req.setDeleteInstanceDir(false);
       req.setCoreName("corex");
       req.process(client);
     }
diff --git a/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java
index f996529c5c4..bc28036665e 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/QueryElevationComponentTest.java
@@ -22,11 +22,10 @@ import static org.apache.solr.common.params.CursorMarkParams.CURSOR_MARK_START;
 import static org.apache.solr.common.util.Utils.fromJSONString;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1260,18 +1259,18 @@ public class QueryElevationComponentTest extends SolrTestCaseJ4 {
 
   // write an elevation config file to boost some docs
   private void writeElevationConfigFile(File file, String query, String... ids) throws Exception {
-    PrintWriter out =
-        new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
-    out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
-    out.println("<elevate>");
-    out.println("<query text=\"" + query + "\">");
-    for (String id : ids) {
-      out.println(" <doc id=\"" + id + "\"/>");
+    try (PrintWriter out =
+        new PrintWriter(Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8))) {
+      out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+      out.println("<elevate>");
+      out.println("<query text=\"" + query + "\">");
+      for (String id : ids) {
+        out.println(" <doc id=\"" + id + "\"/>");
+      }
+      out.println("</query>");
+      out.println("</elevate>");
+      out.flush();
     }
-    out.println("</query>");
-    out.println("</elevate>");
-    out.flush();
-    out.close();
 
     if (log.isInfoEnabled()) {
       log.info("OUT: {}", file.getAbsolutePath());
diff --git a/solr/core/src/test/org/apache/solr/handler/tagger/XmlInterpolationTest.java b/solr/core/src/test/org/apache/solr/handler/tagger/XmlInterpolationTest.java
index 284191403e0..38b24490d26 100644
--- a/solr/core/src/test/org/apache/solr/handler/tagger/XmlInterpolationTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/tagger/XmlInterpolationTest.java
@@ -31,12 +31,12 @@ import java.util.List;
 import java.util.Locale;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.analysis.charfilter.HTMLStripCharFilter;
 import org.apache.lucene.analysis.core.WhitespaceTokenizer;
 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 import org.junit.AfterClass;
@@ -101,8 +101,7 @@ public class XmlInterpolationTest extends TaggerTestCase {
   }
 
   protected void assertXmlTag(String docText, boolean expected) throws Exception {
-    final SolrQueryRequest req = reqDoc(docText);
-    try { // 5.4 and beyond we can use try-with-resources
+    try (SolrQueryRequest req = reqDoc(docText)) {
       final SolrQueryResponse rsp = h.queryAndResponse(req.getParams().get("qt"), req);
       final TestTag[] testTags = pullTagsFromResponse(req, rsp);
       if (!expected) {
@@ -112,8 +111,6 @@ public class XmlInterpolationTest extends TaggerTestCase {
         final TestTag tag = testTags[0];
         validateXml(insertAnchorAtOffsets(docText, tag.startOffset, tag.endOffset, tag.docName));
       }
-    } finally {
-      req.close();
     }
   }
 
@@ -222,6 +219,6 @@ public class XmlInterpolationTest extends TaggerTestCase {
     } finally {
       IOUtils.closeQuietly(ts);
     }
-    return result.toArray(new String[result.size()]);
+    return result.toArray(new String[0]);
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGraphiteReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGraphiteReporterTest.java
index 385ebc85733..49e0cef9824 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGraphiteReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrGraphiteReporterTest.java
@@ -22,12 +22,12 @@ import java.io.InputStreamReader;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.NodeConfig;
@@ -56,8 +56,7 @@ public class SolrGraphiteReporterTest extends SolrTestCaseJ4 {
       // define the port where MockGraphite is running
       System.setProperty("mock-graphite-port", String.valueOf(mock.port));
       String solrXml =
-          FileUtils.readFileToString(
-              Paths.get(home.toString(), "solr-graphitereporter.xml").toFile(), "UTF-8");
+          Files.readString(home.resolve("solr-graphitereporter.xml"), StandardCharsets.UTF_8);
       NodeConfig cfg = SolrXmlConfig.fromString(home, solrXml);
       CoreContainer cc =
           createCoreContainer(
diff --git a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
index 4c443c38fb1..aac67dbc34a 100644
--- a/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
+++ b/solr/core/src/test/org/apache/solr/metrics/reporters/SolrSlf4jReporterTest.java
@@ -18,10 +18,11 @@
 package org.apache.solr.metrics.reporters;
 
 import java.lang.invoke.MethodHandles;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Map;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.core.CoreContainer;
@@ -49,8 +50,7 @@ public class SolrSlf4jReporterTest extends SolrTestCaseJ4 {
     System.setProperty("solr.test.sys.prop2", "proptwo");
 
     String solrXml =
-        FileUtils.readFileToString(
-            Paths.get(home.toString(), "solr-slf4jreporter.xml").toFile(), "UTF-8");
+        Files.readString(home.resolve("solr-slf4jreporter.xml"), StandardCharsets.UTF_8);
     NodeConfig cfg = SolrXmlConfig.fromString(home, solrXml);
     CoreContainer cc =
         createCoreContainer(
diff --git a/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java b/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java
index 721eed3a206..5f9da169a9a 100644
--- a/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java
+++ b/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java
@@ -21,11 +21,9 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
 import java.net.URL;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.tests.util.LuceneTestCase;
 import org.apache.solr.SolrJettyTestBase;
 import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
@@ -90,7 +88,7 @@ public class TestRemoteStreaming extends SolrJettyTestBase {
             + "/"
             + DEFAULT_TEST_COLLECTION_NAME
             + "/debug/dump?wt=xml&stream.url="
-            + URLEncoder.encode(streamUrl, "UTF-8");
+            + URLEncoder.encode(streamUrl, StandardCharsets.UTF_8);
     String content = attemptHttpGet(getUrl);
     assertTrue(content.contains("1234"));
   }
@@ -98,13 +96,10 @@ public class TestRemoteStreaming extends SolrJettyTestBase {
   private String attemptHttpGet(String getUrl) throws IOException {
     Object obj = new URL(getUrl).getContent();
     if (obj instanceof InputStream) {
-      InputStream inputStream = (InputStream) obj;
-      try {
+      try (InputStream inputStream = (InputStream) obj) {
         StringWriter strWriter = new StringWriter();
         new InputStreamReader(inputStream, StandardCharsets.UTF_8).transferTo(strWriter);
         return strWriter.toString();
-      } finally {
-        IOUtils.closeQuietly(inputStream);
       }
     }
     return null;
@@ -123,13 +118,13 @@ public class TestRemoteStreaming extends SolrJettyTestBase {
   }
 
   /** Compose an HTTP GET url that will delete all the data. */
-  private String makeDeleteAllUrl() throws UnsupportedEncodingException {
+  private String makeDeleteAllUrl() {
     String deleteQuery = "<delete><query>*:*</query></delete>";
     return jettySolrRunner.getBaseUrl().toString()
         + "/"
         + DEFAULT_TEST_COLLECTION_NAME
         + "/update?commit=true&stream.body="
-        + URLEncoder.encode(deleteQuery, "UTF-8");
+        + URLEncoder.encode(deleteQuery, StandardCharsets.UTF_8);
   }
 
   private boolean searchFindsIt() throws SolrServerException, IOException {
diff --git a/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java b/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
index fc676549396..329cef1b13b 100644
--- a/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
+++ b/solr/core/src/test/org/apache/solr/response/TestRawTransformer.java
@@ -16,7 +16,6 @@
  */
 package org.apache.solr.response;
 
-import java.io.File;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -25,7 +24,6 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Properties;
 import java.util.regex.Pattern;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -72,16 +70,14 @@ public class TestRawTransformer extends SolrCloudTestCase {
 
   private static void initStandalone() throws Exception {
     initCore("solrconfig-minimal.xml", "schema_latest.xml");
-    File homeDir = createTempDir().toFile();
-    final File collDir = new File(homeDir, "collection1");
-    final File confDir = collDir.toPath().resolve("conf").toFile();
-    confDir.mkdirs();
-    FileUtils.copyFile(
-        new File(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), new File(homeDir, "solr.xml"));
+    Path homeDir = createTempDir();
+    final Path collDir = homeDir.resolve("collection1");
+    final Path confDir = collDir.resolve("conf");
+    Files.createDirectories(confDir);
+    Files.copy(Path.of(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), homeDir.resolve("solr.xml"));
     String src_dir = TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(src_dir, "schema_latest.xml"), new File(confDir, "schema.xml"));
-    FileUtils.copyFile(
-        new File(src_dir, "solrconfig-minimal.xml"), new File(confDir, "solrconfig.xml"));
+    Files.copy(Path.of(src_dir, "schema_latest.xml"), confDir.resolve("schema.xml"));
+    Files.copy(Path.of(src_dir, "solrconfig-minimal.xml"), confDir.resolve("solrconfig.xml"));
     for (String file :
         new String[] {
           "solrconfig.snippet.randomindexconfig.xml",
@@ -90,12 +86,14 @@ public class TestRawTransformer extends SolrCloudTestCase {
           "protwords.txt",
           "currency.xml"
         }) {
-      FileUtils.copyFile(new File(src_dir, file), new File(confDir, file));
+      Files.copy(Path.of(src_dir, file), confDir.resolve(file));
     }
-    Files.createFile(collDir.toPath().resolve("core.properties"));
+    Files.createFile(collDir.resolve("core.properties"));
     Properties nodeProperties = new Properties();
     nodeProperties.setProperty("solr.data.dir", h.getCore().getDataDir());
-    JSR = new JettySolrRunner(homeDir.getAbsolutePath(), nodeProperties, buildJettyConfig("/solr"));
+    JSR =
+        new JettySolrRunner(
+            homeDir.toAbsolutePath().toString(), nodeProperties, buildJettyConfig("/solr"));
   }
 
   private static void initCloud() throws Exception {
diff --git a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java
index 40091a7bfba..461fa4c9560 100644
--- a/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java
+++ b/solr/core/src/test/org/apache/solr/response/transform/TestSubQueryTransformer.java
@@ -17,6 +17,7 @@
 package org.apache.solr.response.transform;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -24,7 +25,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Random;
 import java.util.StringTokenizer;
-import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
diff --git a/solr/core/src/test/org/apache/solr/schema/ExternalFileFieldSortTest.java b/solr/core/src/test/org/apache/solr/schema/ExternalFileFieldSortTest.java
index 1f5a9423ab6..1a554d551b5 100644
--- a/solr/core/src/test/org/apache/solr/schema/ExternalFileFieldSortTest.java
+++ b/solr/core/src/test/org/apache/solr/schema/ExternalFileFieldSortTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.solr.schema;
 
-import java.io.File;
 import java.io.IOException;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.junit.Test;
@@ -28,8 +28,7 @@ public class ExternalFileFieldSortTest extends SolrTestCaseJ4 {
   static void updateExternalFile() throws IOException {
     final String testHome = SolrTestCaseJ4.getFile("solr/collection1").getParent();
     String filename = "external_eff";
-    FileUtils.copyFile(
-        new File(testHome + "/" + filename), new File(h.getCore().getDataDir() + "/" + filename));
+    Files.copy(Path.of(testHome, filename), Path.of(h.getCore().getDataDir(), filename));
   }
 
   private void addDocuments() {
diff --git a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java
index 97d5437ccba..87fbe5b2d12 100644
--- a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java
+++ b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java
@@ -16,15 +16,14 @@
  */
 package org.apache.solr.schema;
 
-import java.io.File;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.Properties;
-import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrJettyTestBase;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
@@ -42,39 +41,35 @@ public class TestBinaryField extends SolrJettyTestBase {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
-    File homeDir = createTempDir().toFile();
+    Path homeDir = createTempDir();
 
-    File collDir = new File(homeDir, "collection1");
-    File dataDir = new File(collDir, "data");
-    File confDir = new File(collDir, "conf");
+    Path collDir = homeDir.resolve("collection1");
+    Path dataDir = collDir.resolve("data");
+    Path confDir = collDir.resolve("conf");
 
-    homeDir.mkdirs();
-    collDir.mkdirs();
-    dataDir.mkdirs();
-    confDir.mkdirs();
+    Files.createDirectories(homeDir);
+    Files.createDirectories(collDir);
+    Files.createDirectories(dataDir);
+    Files.createDirectories(confDir);
 
-    FileUtils.copyFile(
-        new File(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), new File(homeDir, "solr.xml"));
+    Files.copy(Path.of(SolrTestCaseJ4.TEST_HOME(), "solr.xml"), homeDir.resolve("solr.xml"));
 
     String src_dir = TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(
-        new File(src_dir, "schema-binaryfield.xml"), new File(confDir, "schema.xml"));
-    FileUtils.copyFile(
-        new File(src_dir, "solrconfig-basic.xml"), new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        new File(src_dir, "solrconfig.snippet.randomindexconfig.xml"),
-        new File(confDir, "solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(Path.of(src_dir, "schema-binaryfield.xml"), confDir.resolve("schema.xml"));
+    Files.copy(Path.of(src_dir, "solrconfig-basic.xml"), confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        Path.of(src_dir, "solrconfig.snippet.randomindexconfig.xml"),
+        confDir.resolve("solrconfig.snippet.randomindexconfig.xml"));
 
     try (Writer w =
         new OutputStreamWriter(
-            Files.newOutputStream(collDir.toPath().resolve("core.properties")),
-            StandardCharsets.UTF_8)) {
+            Files.newOutputStream(collDir.resolve("core.properties")), StandardCharsets.UTF_8)) {
       Properties coreProps = new Properties();
       coreProps.put("name", "collection1");
       coreProps.store(w, "");
     }
 
-    createAndStartJetty(homeDir.getAbsolutePath());
+    createAndStartJetty(homeDir.toAbsolutePath().toString());
   }
 
   public void testSimple() throws Exception {
diff --git a/solr/core/src/test/org/apache/solr/schema/TestCollationField.java b/solr/core/src/test/org/apache/solr/schema/TestCollationField.java
index 2a9b8d65142..22049aa78dd 100644
--- a/solr/core/src/test/org/apache/solr/schema/TestCollationField.java
+++ b/solr/core/src/test/org/apache/solr/schema/TestCollationField.java
@@ -16,13 +16,12 @@
  */
 package org.apache.solr.schema;
 
-import java.io.File;
-import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.text.Collator;
 import java.text.RuleBasedCollator;
 import java.util.Locale;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.BeforeClass;
 
@@ -56,21 +55,23 @@ public class TestCollationField extends SolrTestCaseJ4 {
    */
   public static String setupSolrHome() throws Exception {
     // make a solr home underneath the test's TEMP_DIR
-    File tmpFile = createTempDir("collation1").toFile();
+    Path tmpFile = createTempDir("collation1");
 
     // make data and conf dirs
-    new File(tmpFile, "data").mkdir();
-    File confDir = new File(tmpFile + "/collection1", "conf");
-    confDir.mkdirs();
+    Files.createDirectories(tmpFile.resolve("data"));
+    Path confDir = tmpFile.resolve("collection1").resolve("conf");
+    Files.createDirectories(confDir);
 
     // copy over configuration files
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig-basic.xml"), new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml"),
-        new File(confDir, "solrconfig.snippet.randomindexconfig.xml"));
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/schema-collate.xml"), new File(confDir, "schema.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig-basic.xml").toPath(),
+        confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml").toPath(),
+        confDir.resolve("solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/schema-collate.xml").toPath(),
+        confDir.resolve("schema.xml"));
 
     // generate custom collation rules (DIN 5007-2), saving to customrules.dat
     RuleBasedCollator baseCollator =
@@ -84,11 +85,9 @@ public class TestCollationField extends SolrTestCaseJ4 {
     RuleBasedCollator tailoredCollator =
         new RuleBasedCollator(baseCollator.getRules() + DIN5007_2_tailorings);
     String tailoredRules = tailoredCollator.getRules();
-    FileOutputStream os = new FileOutputStream(new File(confDir, "customrules.dat"));
-    IOUtils.write(tailoredRules, os, "UTF-8");
-    os.close();
+    Files.writeString(confDir.resolve("customrules.dat"), tailoredRules, StandardCharsets.UTF_8);
 
-    return tmpFile.getAbsolutePath();
+    return tmpFile.toAbsolutePath().toString();
   }
 
   /**
diff --git a/solr/core/src/test/org/apache/solr/schema/TestCollationFieldDocValues.java b/solr/core/src/test/org/apache/solr/schema/TestCollationFieldDocValues.java
index c9d76693d08..b1433df1f6f 100644
--- a/solr/core/src/test/org/apache/solr/schema/TestCollationFieldDocValues.java
+++ b/solr/core/src/test/org/apache/solr/schema/TestCollationFieldDocValues.java
@@ -16,13 +16,12 @@
  */
 package org.apache.solr.schema;
 
-import java.io.File;
-import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.text.Collator;
 import java.text.RuleBasedCollator;
 import java.util.Locale;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.BeforeClass;
 
@@ -56,21 +55,23 @@ public class TestCollationFieldDocValues extends SolrTestCaseJ4 {
    */
   public static String setupSolrHome() throws Exception {
     // make a solr home underneath the test's TEMP_DIR
-    File tmpFile = createTempDir("collation1").toFile();
+    Path tmpFile = createTempDir("collation1");
 
     // make data and conf dirs
-    new File(tmpFile, "data").mkdir();
-    File confDir = new File(tmpFile + "/collection1", "conf");
-    confDir.mkdirs();
+    Files.createDirectories(tmpFile.resolve("data"));
+    Path confDir = tmpFile.resolve("collection1").resolve("conf");
+    Files.createDirectories(confDir);
 
     // copy over configuration files
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig-basic.xml"), new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml"),
-        new File(confDir, "solrconfig.snippet.randomindexconfig.xml"));
-    FileUtils.copyFile(
-        getFile("solr/collection1/conf/schema-collate-dv.xml"), new File(confDir, "schema.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig-basic.xml").toPath(),
+        confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml").toPath(),
+        confDir.resolve("solrconfig.snippet.randomindexconfig.xml"));
+    Files.copy(
+        getFile("solr/collection1/conf/schema-collate-dv.xml").toPath(),
+        confDir.resolve("schema.xml"));
 
     // generate custom collation rules (DIN 5007-2), saving to customrules.dat
     RuleBasedCollator baseCollator =
@@ -84,11 +85,9 @@ public class TestCollationFieldDocValues extends SolrTestCaseJ4 {
     RuleBasedCollator tailoredCollator =
         new RuleBasedCollator(baseCollator.getRules() + DIN5007_2_tailorings);
     String tailoredRules = tailoredCollator.getRules();
-    FileOutputStream os = new FileOutputStream(new File(confDir, "customrules.dat"));
-    IOUtils.write(tailoredRules, os, "UTF-8");
-    os.close();
+    Files.writeString(confDir.resolve("customrules.dat"), tailoredRules, StandardCharsets.UTF_8);
 
-    return tmpFile.getAbsolutePath();
+    return tmpFile.toAbsolutePath().toString();
   }
 
   /**
diff --git a/solr/core/src/test/org/apache/solr/schema/TestManagedSchema.java b/solr/core/src/test/org/apache/solr/schema/TestManagedSchema.java
index c4090b1897b..15c5cd66259 100644
--- a/solr/core/src/test/org/apache/solr/schema/TestManagedSchema.java
+++ b/solr/core/src/test/org/apache/solr/schema/TestManagedSchema.java
@@ -17,15 +17,15 @@
 package org.apache.solr.schema;
 
 import java.io.File;
-import java.io.FileInputStream;
+import java.io.InputStream;
 import java.lang.invoke.MethodHandles;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.regex.Pattern;
 import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.util.NamedList;
@@ -86,7 +86,7 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
   public void testUpgrade() throws Exception {
     File managedSchemaFile = new File(tmpConfDir, "managed-schema.xml");
     assertTrue(managedSchemaFile.exists());
-    String managedSchema = FileUtils.readFileToString(managedSchemaFile, "UTF-8");
+    String managedSchema = Files.readString(managedSchemaFile.toPath(), StandardCharsets.UTF_8);
     assertTrue(managedSchema.contains("DO NOT EDIT"));
     File upgradedOriginalSchemaFile = new File(tmpConfDir, "schema-minimal.xml.bak");
     assertTrue(upgradedOriginalSchemaFile.exists());
@@ -101,7 +101,7 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
     initCore("solrconfig-managed-schema.xml", "schema-minimal.xml", tmpSolrHome.getPath());
     File managedSchemaFile = new File(tmpConfDir, "managed-schema.xml");
     assertTrue(managedSchemaFile.exists());
-    String managedSchema = FileUtils.readFileToString(managedSchemaFile, "UTF-8");
+    String managedSchema = Files.readString(managedSchemaFile.toPath(), StandardCharsets.UTF_8);
     assertTrue(managedSchema.contains("DO NOT EDIT"));
     File upgradedOriginalSchemaFile = new File(tmpConfDir, "schema-minimal.xml.bak");
     assertTrue(upgradedOriginalSchemaFile.exists());
@@ -210,7 +210,8 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
         tmpSolrHome.getPath());
 
     assertTrue(managedSchemaFile.exists());
-    String managedSchemaContents = FileUtils.readFileToString(managedSchemaFile, "UTF-8");
+    String managedSchemaContents =
+        Files.readString(managedSchemaFile.toPath(), StandardCharsets.UTF_8);
     assertFalse(managedSchemaContents.contains("\"new_field\""));
 
     Map<String, Object> options = new HashMap<>();
@@ -223,9 +224,9 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
     h.getCore().setLatestSchema(newSchema);
 
     assertTrue(managedSchemaFile.exists());
-    FileInputStream stream = new FileInputStream(managedSchemaFile);
-    managedSchemaContents = IOUtils.toString(stream, "UTF-8");
-    stream.close(); // Explicitly close so that Windows can delete this file
+    try (InputStream stream = Files.newInputStream(managedSchemaFile.toPath())) {
+      managedSchemaContents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
+    }
     assertTrue(
         managedSchemaContents.contains(
             "<field name=\"new_field\" type=\"string\" stored=\"false\"/>"));
@@ -244,7 +245,8 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
         tmpSolrHome.getPath());
 
     assertTrue(managedSchemaFile.exists());
-    String managedSchemaContents = FileUtils.readFileToString(managedSchemaFile, "UTF-8");
+    String managedSchemaContents =
+        Files.readString(managedSchemaFile.toPath(), StandardCharsets.UTF_8);
     assertFalse(managedSchemaContents.contains("\"new_field\""));
 
     clearIndex();
@@ -483,7 +485,8 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
         tmpSolrHome.getPath());
 
     assertTrue(managedSchemaFile.exists());
-    String managedSchemaContents = FileUtils.readFileToString(managedSchemaFile, "UTF-8");
+    String managedSchemaContents =
+        Files.readString(managedSchemaFile.toPath(), StandardCharsets.UTF_8);
     assertFalse(managedSchemaContents.contains("\"new_field\""));
 
     Map<String, Object> options = new HashMap<>();
@@ -502,9 +505,9 @@ public class TestManagedSchema extends AbstractBadConfigTestBase {
     initCore();
 
     assertTrue(managedSchemaFile.exists());
-    FileInputStream stream = new FileInputStream(managedSchemaFile);
-    managedSchemaContents = IOUtils.toString(stream, "UTF-8");
-    stream.close(); // Explicitly close so that Windows can delete this file
+    try (InputStream stream = Files.newInputStream(managedSchemaFile.toPath())) {
+      managedSchemaContents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
+    }
     assertTrue(
         managedSchemaContents.contains(
             "<field name=\"new_field\" type=\"string\" stored=\"false\"/>"));
diff --git a/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java b/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java
index 0078ff9b01e..292c6f55f3c 100644
--- a/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java
+++ b/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java
@@ -16,10 +16,10 @@
  */
 package org.apache.solr.search.function;
 
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -44,16 +44,11 @@ public class TestFunctionQuery extends SolrTestCaseJ4 {
 
   static long start = System.nanoTime();
 
-  void makeExternalFile(String field, String contents) {
+  void makeExternalFile(String field, String contents) throws IOException {
     String dir = h.getCore().getDataDir();
     String filename = dir + "/external_" + field + "." + (start++);
 
-    try (Writer out =
-        new OutputStreamWriter(new FileOutputStream(filename), StandardCharsets.UTF_8)) {
-      out.write(contents);
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
+    Files.writeString(Path.of(filename), contents, StandardCharsets.UTF_8);
   }
 
   void createIndex(String field, int... values) {
@@ -284,7 +279,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 {
   }
 
   @Test
-  public void testExternalFileFieldStringKeys() {
+  public void testExternalFileFieldStringKeys() throws IOException {
     clearIndex();
 
     final String extField = "foo_extfs";
@@ -298,7 +293,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 {
   }
 
   @Test
-  public void testExternalFileFieldNumericKey() {
+  public void testExternalFileFieldNumericKey() throws IOException {
     clearIndex();
 
     final String extField = "eff_trie";
@@ -1023,7 +1018,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 {
    * esoteric field names
    */
   @Test
-  public void testExternalFieldValueSourceParser() {
+  public void testExternalFieldValueSourceParser() throws IOException {
     clearIndex();
 
     String field = "CoMpleX fieldName _extf";
diff --git a/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java
index e42a6b89578..6a51f06442c 100644
--- a/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/security/AuditLoggerIntegrationTest.java
@@ -34,12 +34,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.lang.invoke.MethodHandles;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -48,8 +50,6 @@ import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.lucene.tests.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
@@ -258,8 +258,10 @@ public class AuditLoggerIntegrationTest extends SolrCloudAuthTestCase {
     expectThrows(
         FileNotFoundException.class,
         () -> {
-          IOUtils.toString(
-              new URL(baseUrl.replace("/solr", "") + "/api/node/foo"), StandardCharsets.UTF_8);
+          try (InputStream is =
+              new URL(baseUrl.replace("/solr", "") + "/api/node/foo").openStream()) {
+            new String(is.readAllBytes(), StandardCharsets.UTF_8);
+          }
         });
     final List<AuditEvent> events = testHarness.get().receiver.waitForAuditEvents(1);
     assertAuditEvent(events.get(0), ERROR, "/api/node/foo", ADMIN, null, 404);
@@ -509,8 +511,8 @@ public class AuditLoggerIntegrationTest extends SolrCloudAuthTestCase {
       boolean async, String semaphoreName, boolean enableAuth, String... muteRulesJson)
       throws Exception {
     String securityJson =
-        FileUtils.readFileToString(
-            TEST_PATH().resolve("security").resolve("auditlog_plugin_security.json").toFile(),
+        Files.readString(
+            TEST_PATH().resolve("security").resolve("auditlog_plugin_security.json"),
             StandardCharsets.UTF_8);
     securityJson = securityJson.replace("_PORT_", Integer.toString(testHarness.get().callbackPort));
     securityJson = securityJson.replace("_ASYNC_", Boolean.toString(async));
diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
index 427d598b232..4c69a43a489 100644
--- a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
@@ -32,7 +32,6 @@ import java.util.Map;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpPost;
@@ -452,7 +451,7 @@ public class BasicAuthIntegrationTest extends SolrCloudAuthTestCase {
     httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8)));
     httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
     r = cl.execute(httpPost);
-    String response = IOUtils.toString(r.getEntity().getContent(), StandardCharsets.UTF_8);
+    String response = new String(r.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8);
     assertEquals(
         "Non-200 response code. Response was " + response, 200, r.getStatusLine().getStatusCode());
     assertFalse("Response contained errors: " + response, response.contains("errorMessages"));
diff --git a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
index 6f7269be9a0..1f3bd062121 100644
--- a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
+++ b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
@@ -26,6 +26,7 @@ import static org.apache.solr.security.BasicAuthStandaloneTest.doHttpPostWithHea
 import java.io.IOException;
 import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.security.Principal;
 import java.util.List;
 import java.util.Map;
@@ -34,7 +35,6 @@ import java.util.function.Predicate;
 import javax.servlet.FilterChain;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.FileUtils;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
@@ -98,8 +98,8 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
 
       // Initialize security.json with multiple auth plugins configured
       String multiAuthPluginSecurityJson =
-          FileUtils.readFileToString(
-              TEST_PATH().resolve("security").resolve("multi_auth_plugin_security.json").toFile(),
+          Files.readString(
+              TEST_PATH().resolve("security").resolve("multi_auth_plugin_security.json"),
               StandardCharsets.UTF_8);
       securityConfHandler.persistConf(
           new SecurityConfHandler.SecurityConfig()
diff --git a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java
index b845cb179bd..179eef4c7cb 100644
--- a/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java
+++ b/solr/core/src/test/org/apache/solr/servlet/CacheHeaderTest.java
@@ -17,11 +17,10 @@
 package org.apache.solr.servlet;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Date;
 import org.apache.http.Header;
@@ -271,11 +270,9 @@ public class CacheHeaderTest extends CacheHeaderTestBase {
 
   protected File makeFile(String contents, String charset) {
     try {
-      File f = createTempFile("cachetest", "csv").toFile();
-      try (Writer out = new OutputStreamWriter(new FileOutputStream(f), charset)) {
-        out.write(contents);
-      }
-      return f;
+      Path f = createTempFile("cachetest", "csv");
+      Files.writeString(f, contents, Charset.forName(charset));
+      return f.toFile();
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
diff --git a/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java
index 62fd7fa6c22..b5d312eb021 100644
--- a/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java
+++ b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java
@@ -19,7 +19,9 @@ package org.apache.solr.servlet;
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import org.apache.http.Header;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.methods.HttpGet;
@@ -40,9 +42,10 @@ public class ResponseHeaderTest extends SolrJettyTestBase {
     solrHomeDirectory = createTempDir().toFile();
     setupJettyTestHome(solrHomeDirectory, "collection1");
     String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(
-        new File(top, "solrconfig-headers.xml"),
-        new File(solrHomeDirectory + "/collection1/conf", "solrconfig.xml"));
+    Files.copy(
+        Path.of(top, "solrconfig-headers.xml"),
+        Path.of(solrHomeDirectory + "/collection1/conf", "solrconfig.xml"),
+        StandardCopyOption.REPLACE_EXISTING);
     createAndStartJetty(solrHomeDirectory.getAbsolutePath());
   }
 
diff --git a/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java b/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
index 561211e8b7c..5b0d0d1c285 100644
--- a/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
+++ b/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
@@ -129,7 +129,10 @@ public class SolrRequestParserTest extends SolrTestCaseJ4 {
     URL url = getClass().getResource("/README");
     assertNotNull("Missing file 'README' in test-resources root folder.", url);
 
-    byte[] bytes = IOUtils.toByteArray(url);
+    final byte[] bytes;
+    try (InputStream inputStream = url.openStream()) {
+      bytes = inputStream.readAllBytes();
+    }
 
     SolrCore core = h.getCore();
 
@@ -142,7 +145,7 @@ public class SolrRequestParserTest extends SolrTestCaseJ4 {
         parser.buildRequestFrom(core, new MultiMapSolrParams(args), streams)) {
       assertEquals(1, streams.size());
       try (InputStream in = streams.get(0).getStream()) {
-        assertArrayEquals(bytes, IOUtils.toByteArray(in));
+        assertArrayEquals(bytes, in.readAllBytes());
       }
     }
   }
@@ -165,7 +168,7 @@ public class SolrRequestParserTest extends SolrTestCaseJ4 {
         parser.buildRequestFrom(core, new MultiMapSolrParams(args), streams)) {
       assertEquals(1, streams.size());
       try (InputStream in = streams.get(0).getStream()) {
-        assertArrayEquals(bytes, IOUtils.toByteArray(in));
+        assertArrayEquals(bytes, in.readAllBytes());
       }
     }
   }
diff --git a/solr/core/src/test/org/apache/solr/update/AddBlockUpdateTest.java b/solr/core/src/test/org/apache/solr/update/AddBlockUpdateTest.java
index 385cf901d5d..b3ed3c05249 100644
--- a/solr/core/src/test/org/apache/solr/update/AddBlockUpdateTest.java
+++ b/solr/core/src/test/org/apache/solr/update/AddBlockUpdateTest.java
@@ -19,6 +19,7 @@ package org.apache.solr.update;
 import static org.hamcrest.core.StringContains.containsString;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -45,7 +46,6 @@ import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
-import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.TermQuery;
 import org.apache.lucene.search.TermRangeQuery;
diff --git a/solr/core/src/test/org/apache/solr/util/TestSystemIdResolver.java b/solr/core/src/test/org/apache/solr/util/TestSystemIdResolver.java
index d7bf4228011..71ba80b4bd1 100644
--- a/solr/core/src/test/org/apache/solr/util/TestSystemIdResolver.java
+++ b/solr/core/src/test/org/apache/solr/util/TestSystemIdResolver.java
@@ -20,9 +20,9 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.Arrays;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.util.ResourceLoader;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.core.SolrResourceLoader;
 import org.xml.sax.InputSource;
 
diff --git a/solr/modules/analysis-extras/build.gradle b/solr/modules/analysis-extras/build.gradle
index 8fa1c000adb..1741cc17772 100644
--- a/solr/modules/analysis-extras/build.gradle
+++ b/solr/modules/analysis-extras/build.gradle
@@ -24,7 +24,6 @@ dependencies {
 
   implementation project(':solr:solrj')
 
-  implementation 'commons-io:commons-io'
   implementation 'com.ibm.icu:icu4j'
   implementation 'org.apache.lucene:lucene-analysis-icu'
   runtimeOnly 'org.apache.lucene:lucene-analysis-morfologik'
@@ -38,6 +37,7 @@ dependencies {
 
   testImplementation project(':solr:test-framework')
   testImplementation 'org.apache.lucene:lucene-analysis-common'
+  testImplementation 'commons-io:commons-io'
   testImplementation 'junit:junit'
   testImplementation('org.mockito:mockito-core', {
     exclude group: "net.bytebuddy", module: "byte-buddy-agent"
diff --git a/solr/modules/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java b/solr/modules/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
index af15435b207..7931d58393a 100644
--- a/solr/modules/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
+++ b/solr/modules/analysis-extras/src/java/org/apache/solr/schema/ICUCollationField.java
@@ -28,7 +28,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.TokenStream;
 import org.apache.lucene.analysis.icu.ICUCollationKeyAnalyzer;
@@ -232,16 +231,12 @@ public class ICUCollationField extends FieldType {
    * as # might be in the rules!
    */
   static Collator createFromRules(String fileName, ResourceLoader loader) {
-    InputStream input = null;
-    try {
-      input = loader.openResource(fileName);
-      String rules = IOUtils.toString(input, StandardCharsets.UTF_8);
+    try (InputStream input = loader.openResource(fileName)) {
+      String rules = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       return new RuleBasedCollator(rules);
     } catch (Exception e) {
       // io error or invalid rules
       throw new RuntimeException(e);
-    } finally {
-      IOUtils.closeQuietly(input);
     }
   }
 
diff --git a/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationField.java b/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationField.java
index 8b5294d0b34..7378f8f7a5b 100644
--- a/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationField.java
+++ b/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationField.java
@@ -20,10 +20,9 @@ import com.ibm.icu.text.Collator;
 import com.ibm.icu.text.RuleBasedCollator;
 import com.ibm.icu.util.ULocale;
 import java.io.ByteArrayInputStream;
-import java.io.File;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Path;
 import org.apache.lucene.analysis.util.FilesystemResourceLoader;
 import org.apache.lucene.util.ResourceLoader;
 import org.apache.solr.SolrTestCaseJ4;
@@ -59,19 +58,19 @@ public class TestICUCollationField extends SolrTestCaseJ4 {
    * jvm differences with collation). So it's preferable to create this file on-the-fly.
    */
   public static String setupSolrHome() throws Exception {
-    String tmpFile = createTempDir().toFile().getAbsolutePath();
+    Path tmpFile = createTempDir();
     // make data and conf dirs
-    new File(tmpFile + "/collection1", "data").mkdirs();
-    File confDir = new File(tmpFile + "/collection1", "conf");
-    confDir.mkdirs();
+    Files.createDirectories(tmpFile.resolve("collection1").resolve("data"));
+    Path confDir = tmpFile.resolve("collection1").resolve("conf");
+    Files.createDirectories(confDir);
 
     // copy over configuration files
-    FileUtils.copyFile(
-        getFile("analysis-extras/solr/collection1/conf/solrconfig-icucollate.xml"),
-        new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        getFile("analysis-extras/solr/collection1/conf/schema-icucollate.xml"),
-        new File(confDir, "schema.xml"));
+    Files.copy(
+        getFile("analysis-extras/solr/collection1/conf/solrconfig-icucollate.xml").toPath(),
+        confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        getFile("analysis-extras/solr/collection1/conf/schema-icucollate.xml").toPath(),
+        confDir.resolve("schema.xml"));
 
     // generate custom collation rules (DIN 5007-2), saving to customrules.dat
     RuleBasedCollator baseCollator =
@@ -86,7 +85,7 @@ public class TestICUCollationField extends SolrTestCaseJ4 {
         new RuleBasedCollator(baseCollator.getRules() + DIN5007_2_tailorings);
     String tailoredRules = tailoredCollator.getRules();
     final String osFileName = "customrules.dat";
-    Files.writeString(confDir.toPath().resolve(osFileName), tailoredRules, StandardCharsets.UTF_8);
+    Files.writeString(confDir.resolve(osFileName), tailoredRules, StandardCharsets.UTF_8);
 
     assumeWorkingMockito();
 
@@ -96,14 +95,12 @@ public class TestICUCollationField extends SolrTestCaseJ4 {
       Mockito.when(loader.openResource(Mockito.anyString()))
           .thenReturn(new ByteArrayInputStream(tailoredRules.getBytes(StandardCharsets.UTF_8)));
     } else {
-      loader =
-          new FilesystemResourceLoader(
-              confDir.toPath(), TestICUCollationField.class.getClassLoader());
+      loader = new FilesystemResourceLoader(confDir, TestICUCollationField.class.getClassLoader());
     }
     final Collator readCollator = ICUCollationField.createFromRules(osFileName, loader);
     assertEquals(tailoredCollator, readCollator);
 
-    return tmpFile;
+    return tmpFile.toAbsolutePath().toString();
   }
 
   /**
diff --git a/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationFieldDocValues.java b/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationFieldDocValues.java
index 322a9153492..2f1881c19da 100644
--- a/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationFieldDocValues.java
+++ b/solr/modules/analysis-extras/src/test/org/apache/solr/schema/TestICUCollationFieldDocValues.java
@@ -19,10 +19,9 @@ package org.apache.solr.schema;
 import com.ibm.icu.text.Collator;
 import com.ibm.icu.text.RuleBasedCollator;
 import com.ibm.icu.util.ULocale;
-import java.io.File;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
-import org.apache.commons.io.FileUtils;
+import java.nio.file.Path;
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.BeforeClass;
 
@@ -55,20 +54,20 @@ public class TestICUCollationFieldDocValues extends SolrTestCaseJ4 {
    * jvm differences with collation). So it's preferable to create this file on-the-fly.
    */
   public static String setupSolrHome() throws Exception {
-    File tmpFile = createTempDir().toFile();
+    Path tmpFile = createTempDir();
 
     // make data and conf dirs
-    new File(tmpFile + "/collection1", "data").mkdirs();
-    File confDir = new File(tmpFile + "/collection1", "conf");
-    confDir.mkdirs();
+    Files.createDirectories(tmpFile.resolve("collection1").resolve("data"));
+    Path confDir = tmpFile.resolve("collection1").resolve("conf");
+    Files.createDirectories(confDir);
 
     // copy over configuration files
-    FileUtils.copyFile(
-        getFile("analysis-extras/solr/collection1/conf/solrconfig-icucollate.xml"),
-        new File(confDir, "solrconfig.xml"));
-    FileUtils.copyFile(
-        getFile("analysis-extras/solr/collection1/conf/schema-icucollate-dv.xml"),
-        new File(confDir, "schema.xml"));
+    Files.copy(
+        getFile("analysis-extras/solr/collection1/conf/solrconfig-icucollate.xml").toPath(),
+        confDir.resolve("solrconfig.xml"));
+    Files.copy(
+        getFile("analysis-extras/solr/collection1/conf/schema-icucollate-dv.xml").toPath(),
+        confDir.resolve("schema.xml"));
 
     // generate custom collation rules (DIN 5007-2), saving to customrules.dat
     RuleBasedCollator baseCollator =
@@ -82,10 +81,9 @@ public class TestICUCollationFieldDocValues extends SolrTestCaseJ4 {
     RuleBasedCollator tailoredCollator =
         new RuleBasedCollator(baseCollator.getRules() + DIN5007_2_tailorings);
     String tailoredRules = tailoredCollator.getRules();
-    Files.writeString(
-        confDir.toPath().resolve("customrules.dat"), tailoredRules, StandardCharsets.UTF_8);
+    Files.writeString(confDir.resolve("customrules.dat"), tailoredRules, StandardCharsets.UTF_8);
 
-    return tmpFile.getAbsolutePath();
+    return tmpFile.toAbsolutePath().toString();
   }
 
   /**
diff --git a/solr/modules/extraction/build.gradle b/solr/modules/extraction/build.gradle
index 4913a828378..952ebee0424 100644
--- a/solr/modules/extraction/build.gradle
+++ b/solr/modules/extraction/build.gradle
@@ -26,7 +26,6 @@ dependencies {
   implementation 'org.apache.lucene:lucene-core'
   implementation 'org.slf4j:slf4j-api'
 
-  implementation 'commons-io:commons-io'
   implementation 'org.apache.poi:poi'
   implementation 'org.apache.poi:poi-ooxml'
   implementation 'org.apache.tika:tika-core'
diff --git a/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/ExtractingDocumentLoader.java b/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/ExtractingDocumentLoader.java
index 615986b5b81..69e44360f2b 100644
--- a/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/ExtractingDocumentLoader.java
+++ b/solr/modules/extraction/src/java/org/apache/solr/handler/extraction/ExtractingDocumentLoader.java
@@ -21,7 +21,6 @@ import java.io.InputStream;
 import java.io.StringWriter;
 import java.lang.invoke.MethodHandles;
 import java.util.Locale;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.params.UpdateParams;
@@ -147,9 +146,7 @@ public class ExtractingDocumentLoader extends ContentStreamLoader {
         metadata.add(HttpHeaders.CONTENT_TYPE, stream.getContentType());
       }
 
-      InputStream inputStream = null;
-      try {
-        inputStream = stream.getStream();
+      try (InputStream inputStream = stream.getStream()) {
         metadata.add(ExtractingMetadataConstants.STREAM_NAME, stream.getName());
         metadata.add(ExtractingMetadataConstants.STREAM_SOURCE_INFO, stream.getSourceInfo());
         metadata.add(ExtractingMetadataConstants.STREAM_SIZE, String.valueOf(stream.getSize()));
@@ -246,8 +243,6 @@ public class ExtractingDocumentLoader extends ContentStreamLoader {
         }
       } catch (SAXException e) {
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
-      } finally {
-        IOUtils.closeQuietly(inputStream);
       }
     } else {
       throw new SolrException(
diff --git a/solr/modules/hdfs/src/test/org/apache/solr/hdfs/cloud/api/collections/TestHdfsCloudBackupRestore.java b/solr/modules/hdfs/src/test/org/apache/solr/hdfs/cloud/api/collections/TestHdfsCloudBackupRestore.java
index dcd2c73f8ac..38e0e221874 100644
--- a/solr/modules/hdfs/src/test/org/apache/solr/hdfs/cloud/api/collections/TestHdfsCloudBackupRestore.java
+++ b/solr/modules/hdfs/src/test/org/apache/solr/hdfs/cloud/api/collections/TestHdfsCloudBackupRestore.java
@@ -30,7 +30,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
@@ -46,6 +45,7 @@ import org.apache.solr.cloud.ZkConfigSetService;
 import org.apache.solr.cloud.api.collections.AbstractCloudBackupRestoreTestCase;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.backup.BackupManager;
 import org.apache.solr.core.backup.BackupProperties;
diff --git a/solr/modules/hdfs/src/test/org/apache/solr/hdfs/handler/TestHdfsBackupRestoreCore.java b/solr/modules/hdfs/src/test/org/apache/solr/hdfs/handler/TestHdfsBackupRestoreCore.java
index 1ff9729c775..0bdfc507403 100644
--- a/solr/modules/hdfs/src/test/org/apache/solr/hdfs/handler/TestHdfsBackupRestoreCore.java
+++ b/solr/modules/hdfs/src/test/org/apache/solr/hdfs/handler/TestHdfsBackupRestoreCore.java
@@ -24,7 +24,6 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
@@ -48,6 +47,7 @@ import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.core.backup.BackupId;
 import org.apache.solr.core.backup.ShardBackupId;
 import org.apache.solr.handler.BackupRestoreUtils;
diff --git a/solr/modules/jwt-auth/build.gradle b/solr/modules/jwt-auth/build.gradle
index 66eb1a16f42..2553d7381c6 100644
--- a/solr/modules/jwt-auth/build.gradle
+++ b/solr/modules/jwt-auth/build.gradle
@@ -35,7 +35,6 @@ dependencies {
 
   implementation 'org.bitbucket.b_c:jose4j'
 
-  implementation 'commons-io:commons-io'
   implementation 'io.dropwizard.metrics:metrics-core'
   implementation 'org.apache.httpcomponents:httpclient'
   implementation 'org.apache.httpcomponents:httpcore'
diff --git a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java
index 9af08d6a655..a51f2208eea 100644
--- a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java
+++ b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTAuthPlugin.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.security.jwt;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.charset.StandardCharsets;
@@ -44,7 +45,6 @@ import java.util.stream.Collectors;
 import javax.servlet.FilterChain;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpRequest;
 import org.apache.http.client.protocol.HttpClientContext;
@@ -228,7 +228,8 @@ public class JWTAuthPlugin extends AuthenticationPlugin
     if (trustedCerts != null) {
       log.info("Reading trustedCerts PEM from configuration string");
       trustedSslCerts =
-          CryptoKeys.parseX509Certs(IOUtils.toInputStream(trustedCerts, StandardCharsets.UTF_8));
+          CryptoKeys.parseX509Certs(
+              new ByteArrayInputStream(trustedCerts.getBytes(StandardCharsets.UTF_8)));
     }
 
     long jwkCacheDuration =
diff --git a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTIssuerConfig.java b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTIssuerConfig.java
index 9b3d06a4e52..55ccbcc956a 100644
--- a/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTIssuerConfig.java
+++ b/solr/modules/jwt-auth/src/java/org/apache/solr/security/jwt/JWTIssuerConfig.java
@@ -33,7 +33,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.Utils;
 import org.jose4j.http.Get;
@@ -472,7 +471,7 @@ public class JWTIssuerConfig {
             }
           }
           SimpleResponse resp = httpGet.get(url.toString());
-          return parse(IOUtils.toInputStream(resp.getBody(), StandardCharsets.UTF_8));
+          return parse(new ByteArrayInputStream(resp.getBody().getBytes(StandardCharsets.UTF_8)));
         }
       } catch (IOException e) {
         throw new SolrException(
diff --git a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
index 783204666c6..2e87aa0720b 100644
--- a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
+++ b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
@@ -46,7 +46,6 @@ import no.nav.security.mock.oauth2.OAuth2Config;
 import no.nav.security.mock.oauth2.http.MockWebServerWrapper;
 import no.nav.security.mock.oauth2.token.DefaultOAuth2TokenCallback;
 import okhttp3.mockwebserver.MockWebServer;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
@@ -459,7 +458,7 @@ public class JWTAuthPluginIntegrationTest extends SolrCloudAuthTestCase {
     httpPost.setEntity(new ByteArrayEntity(payload.getBytes(UTF_8)));
     httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
     r = cl.execute(httpPost);
-    String response = IOUtils.toString(r.getEntity().getContent(), StandardCharsets.UTF_8);
+    String response = new String(r.getEntity().getContent().readAllBytes(), StandardCharsets.UTF_8);
     assertEquals(
         "Non-200 response code. Response was " + response, 200, r.getStatusLine().getStatusCode());
     assertFalse("Response contained errors: " + response, response.contains("errorMessages"));
diff --git a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java
index 9c5bd7144f8..f40ffee9be9 100644
--- a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java
+++ b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginTest.java
@@ -24,6 +24,7 @@ import static org.apache.solr.security.jwt.JWTAuthPlugin.JWTAuthenticationRespon
 import static org.apache.solr.security.jwt.JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.PRINCIPAL_MISSING;
 import static org.apache.solr.security.jwt.JWTAuthPlugin.JWTAuthenticationResponse.AuthCode.SCOPE_MISSING;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -40,7 +41,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.Utils;
@@ -641,7 +641,8 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
   @Test
   public void parsePemToX509() {
     Collection<X509Certificate> parsed =
-        CryptoKeys.parseX509Certs(IOUtils.toInputStream(trustedPemCert, StandardCharsets.UTF_8));
+        CryptoKeys.parseX509Certs(
+            new ByteArrayInputStream(trustedPemCert.getBytes(StandardCharsets.UTF_8)));
     assertEquals(2, parsed.size());
   }
 
@@ -652,9 +653,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
         CertificateException.class,
         () -> {
           CryptoKeys.parseX509Certs(
-              IOUtils.toInputStream(
-                  "-----BEGIN CERTIFICATE-----\n" + "foo\n" + "-----END CERTIFICATE-----\n",
-                  StandardCharsets.UTF_8));
+              new ByteArrayInputStream(
+                  ("-----BEGIN CERTIFICATE-----\n" + "foo\n" + "-----END CERTIFICATE-----\n")
+                      .getBytes(StandardCharsets.UTF_8)));
         });
   }
 
@@ -663,7 +664,9 @@ public class JWTAuthPluginTest extends SolrTestCaseJ4 {
     Path pemFilePath = JWT_TEST_PATH().resolve("security").resolve("jwt_plugin_idp_cert.pem");
     String cert = CryptoKeys.extractCertificateFromPem(Files.readString(pemFilePath));
     assertEquals(
-        2, CryptoKeys.parseX509Certs(IOUtils.toInputStream(cert, StandardCharsets.UTF_8)).size());
+        2,
+        CryptoKeys.parseX509Certs(new ByteArrayInputStream(cert.getBytes(StandardCharsets.UTF_8)))
+            .size());
   }
 
   @Test
diff --git a/solr/modules/langid/src/java/org/apache/solr/update/processor/OpenNLPLangDetectUpdateProcessorFactory.java b/solr/modules/langid/src/java/org/apache/solr/update/processor/OpenNLPLangDetectUpdateProcessorFactory.java
index 6295dbad2c1..f0c2a2ca485 100644
--- a/solr/modules/langid/src/java/org/apache/solr/update/processor/OpenNLPLangDetectUpdateProcessorFactory.java
+++ b/solr/modules/langid/src/java/org/apache/solr/update/processor/OpenNLPLangDetectUpdateProcessorFactory.java
@@ -19,7 +19,6 @@ package org.apache.solr.update.processor;
 import java.io.IOException;
 import java.io.InputStream;
 import opennlp.tools.langdetect.LanguageDetectorModel;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.SolrCore;
@@ -110,14 +109,10 @@ public class OpenNLPLangDetectUpdateProcessorFactory extends UpdateRequestProces
   }
 
   private void loadModel() throws IOException {
-    InputStream is = null;
-    try {
-      if (modelFile != null) {
-        is = solrResourceLoader.openResource(modelFile);
+    if (modelFile != null) {
+      try (InputStream is = solrResourceLoader.openResource(modelFile)) {
         model = new LanguageDetectorModel(is);
       }
-    } finally {
-      IOUtils.closeQuietly(is);
     }
   }
 
diff --git a/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java b/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
index 28780d1dfed..cefe26d9faa 100644
--- a/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
+++ b/solr/modules/s3-repository/src/test/org/apache/solr/s3/AbstractS3ClientTest.java
@@ -19,8 +19,7 @@ package org.apache.solr.s3;
 import com.adobe.testing.s3mock.junit4.S3MockRule;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.nio.charset.Charset;
-import org.apache.commons.io.IOUtils;
+import java.nio.charset.StandardCharsets;
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.After;
 import org.junit.Before;
@@ -66,7 +65,7 @@ public class AbstractS3ClientTest extends SolrTestCaseJ4 {
    */
   void pushContent(String path, String content) throws S3Exception {
     try (OutputStream output = client.pushStream(path)) {
-      IOUtils.write(content, output, Charset.defaultCharset());
+      output.write(content.getBytes(StandardCharsets.UTF_8));
     } catch (IOException e) {
       throw new S3Exception(e);
     }
diff --git a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
index 16189a10051..44177d41265 100644
--- a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
+++ b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3OutputStreamTest.java
@@ -19,8 +19,7 @@ package org.apache.solr.s3;
 import com.adobe.testing.s3mock.junit4.S3MockRule;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.Charset;
-import org.apache.commons.io.IOUtils;
+import java.nio.charset.StandardCharsets;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.junit.After;
@@ -65,7 +64,7 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
 
     // Check we can re-read same content
     try (InputStream input = s3.getObject(b -> b.bucket(BUCKET).key("byte-by-byte"))) {
-      String read = IOUtils.toString(input, Charset.defaultCharset());
+      String read = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       assertEquals("Contents saved to S3 file did not match expected", "hello", read);
     }
   }
@@ -74,7 +73,7 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
   @Test
   public void testWriteSmallBuffer() throws IOException {
     // must be smaller than S3 part size
-    byte[] buffer = "hello".getBytes(Charset.defaultCharset());
+    byte[] buffer = "hello".getBytes(StandardCharsets.UTF_8);
     // pre-check -- ensure that our test string isn't too big
     assertTrue(buffer.length < S3OutputStream.PART_SIZE);
 
@@ -84,7 +83,7 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
 
     // Check we can re-read same content
     try (InputStream input = s3.getObject(b -> b.bucket(BUCKET).key("small-buffer"))) {
-      String read = IOUtils.toString(input, Charset.defaultCharset());
+      String read = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       assertEquals("hello", read);
     }
   }
@@ -94,7 +93,7 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
   public void testWriteLargeBuffer() throws IOException {
     // must be larger than S3 part size
     String content = RandomStringUtils.randomAlphanumeric(S3OutputStream.PART_SIZE + 1024);
-    byte[] buffer = content.getBytes(Charset.defaultCharset());
+    byte[] buffer = content.getBytes(StandardCharsets.UTF_8);
     // pre-check -- ensure that our test string isn't too small
     assertTrue(buffer.length > S3OutputStream.PART_SIZE);
 
@@ -104,8 +103,8 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
 
     // Check we can re-read same content
     try (InputStream input = s3.getObject(b -> b.bucket(BUCKET).key("large-buffer"))) {
-      String read = IOUtils.toString(input, Charset.defaultCharset());
-      assertEquals(new String(buffer, Charset.defaultCharset()), read);
+      String read = new String(input.readAllBytes(), StandardCharsets.UTF_8);
+      assertEquals(new String(buffer, StandardCharsets.UTF_8), read);
     }
   }
 
@@ -113,20 +112,20 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
   @Test
   public void testFlushSmallBuffer() throws IOException {
     // must be smaller than S3 minimal part size, so flush is a no-op
-    byte[] buffer = "hello".getBytes(Charset.defaultCharset());
+    byte[] buffer = "hello".getBytes(StandardCharsets.UTF_8);
     assertTrue(buffer.length < S3OutputStream.PART_SIZE);
 
     try (S3OutputStream output = new S3OutputStream(s3, "flush-small", BUCKET)) {
       output.write(buffer);
       output.flush();
 
-      buffer = ", world!".getBytes(Charset.defaultCharset());
+      buffer = ", world!".getBytes(StandardCharsets.UTF_8);
       output.write(buffer);
     }
 
     // Check we can re-read same content
     try (InputStream input = s3.getObject(b -> b.bucket(BUCKET).key("flush-small"))) {
-      String read = IOUtils.toString(input, Charset.defaultCharset());
+      String read = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       assertEquals(
           "Flushing a small frame of an S3OutputStream should not impact data written",
           "hello, world!",
@@ -139,20 +138,20 @@ public class S3OutputStreamTest extends SolrTestCaseJ4 {
   public void testFlushLargeBuffer() throws IOException {
     // must be larger than S3 minimal part size, so we actually do something for flush()
     String content = RandomStringUtils.randomAlphanumeric(S3OutputStream.MIN_PART_SIZE + 1024);
-    byte[] buffer = content.getBytes(Charset.defaultCharset());
+    byte[] buffer = content.getBytes(StandardCharsets.UTF_8);
     assertTrue(buffer.length > S3OutputStream.MIN_PART_SIZE);
 
     try (S3OutputStream output = new S3OutputStream(s3, "flush-large", BUCKET)) {
       output.write(buffer);
       output.flush();
 
-      buffer = "some more".getBytes(Charset.defaultCharset());
+      buffer = "some more".getBytes(StandardCharsets.UTF_8);
       output.write(buffer);
     }
 
     // Check we can re-read same content
     try (InputStream input = s3.getObject(b -> b.bucket(BUCKET).key("flush-large"))) {
-      String read = IOUtils.toString(input, Charset.defaultCharset());
+      String read = new String(input.readAllBytes(), StandardCharsets.UTF_8);
       assertEquals(
           "Flushing a large frame of an S3OutputStream should not impact data written",
           content + "some more",
diff --git a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3ReadWriteTest.java b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3ReadWriteTest.java
index 125f7411432..8879879699d 100644
--- a/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3ReadWriteTest.java
+++ b/solr/modules/s3-repository/src/test/org/apache/solr/s3/S3ReadWriteTest.java
@@ -19,9 +19,8 @@ package org.apache.solr.s3;
 import static org.hamcrest.Matchers.containsString;
 
 import java.io.InputStream;
-import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.Collections;
-import org.apache.commons.io.IOUtils;
 import org.hamcrest.MatcherAssert;
 import org.junit.Test;
 
@@ -34,7 +33,7 @@ public class S3ReadWriteTest extends AbstractS3ClientTest {
     pushContent("/foo", "my blob");
 
     try (InputStream stream = client.pullStream("/foo")) {
-      assertEquals("my blob", IOUtils.toString(stream, Charset.defaultCharset()));
+      assertEquals("my blob", new String(stream.readAllBytes(), StandardCharsets.UTF_8));
     }
   }
 
@@ -70,11 +69,12 @@ public class S3ReadWriteTest extends AbstractS3ClientTest {
     pushContent("/override", "old content");
     pushContent("/override", "new content");
 
-    InputStream stream = client.pullStream("/override");
-    assertEquals(
-        "File contents should have been overridden",
-        "new content",
-        IOUtils.toString(stream, Charset.defaultCharset()));
+    try (InputStream stream = client.pullStream("/override")) {
+      assertEquals(
+          "File contents should have been overridden",
+          "new content",
+          new String(stream.readAllBytes(), StandardCharsets.UTF_8));
+    }
   }
 
   /** Check getting the length of a written file. */
diff --git a/solr/modules/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java b/solr/modules/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
index 6484dad2949..6494e48a2ab 100644
--- a/solr/modules/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
+++ b/solr/modules/scripting/src/java/org/apache/solr/scripting/update/ScriptUpdateProcessorFactory.java
@@ -38,7 +38,7 @@ import javax.script.ScriptEngineFactory;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
 import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
+import org.apache.lucene.util.IOUtils;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.params.ModifiableSolrParams;
@@ -306,9 +306,7 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
       }
 
       scriptEngines.add(new EngineInfo((Invocable) engine, scriptFile));
-      try {
-        Reader scriptSrc = scriptFile.openReader(resourceLoader);
-
+      try (Reader scriptSrc = scriptFile.openReader(resourceLoader)) {
         try {
           try {
             AccessController.doPrivileged(
@@ -328,8 +326,6 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
               SolrException.ErrorCode.SERVER_ERROR,
               "Unable to evaluate script: " + scriptFile.getFileName(),
               e);
-        } finally {
-          IOUtils.closeQuietly(scriptSrc);
         }
       } catch (IOException ioe) {
         throw new SolrException(
@@ -512,7 +508,7 @@ public class ScriptUpdateProcessorFactory extends UpdateRequestProcessorFactory
 
     public Reader openReader(SolrResourceLoader resourceLoader) throws IOException {
       InputStream input = resourceLoader.openResource(fileName);
-      return org.apache.lucene.util.IOUtils.getDecodingReader(input, StandardCharsets.UTF_8);
+      return IOUtils.getDecodingReader(input, StandardCharsets.UTF_8);
     }
   }
 
diff --git a/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/TransformerProvider.java b/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/TransformerProvider.java
index 2db5c944b34..390fc2ceb77 100644
--- a/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/TransformerProvider.java
+++ b/solr/modules/scripting/src/java/org/apache/solr/scripting/xslt/TransformerProvider.java
@@ -27,8 +27,8 @@ import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.stream.StreamSource;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.util.ResourceLoader;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.TimeSource;
 import org.apache.solr.common.util.XMLErrorLogger;
 import org.apache.solr.core.SolrConfig;
diff --git a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
index 7ef4e3dadb0..46b7c45e538 100644
--- a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
+++ b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/exporter/SolrExporterTestBase.java
@@ -26,12 +26,12 @@ import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.HttpStatus;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.Pair;
 import org.apache.solr.prometheus.PrometheusExporterTestBase;
 import org.apache.solr.prometheus.utils.Helpers;
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
index 15c04a798e2..aa523e2f5e0 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttp2SolrClient.java
@@ -20,13 +20,13 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.FileUtils;
 import org.apache.lucene.util.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
@@ -299,12 +299,13 @@ public class TestLBHttp2SolrClient extends SolrTestCaseJ4 {
       dataDir.mkdirs();
       confDir.mkdirs();
 
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrXmlFile()), new File(homeDir, "solr.xml"));
+      Files.copy(
+          SolrTestCaseJ4.getFile(getSolrXmlFile()).toPath(), homeDir.toPath().resolve("solr.xml"));
 
-      File f = new File(confDir, "solrconfig.xml");
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrConfigFile()), f);
-      f = new File(confDir, "schema.xml");
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSchemaFile()), f);
+      Path f = confDir.toPath().resolve("solrconfig.xml");
+      Files.copy(SolrTestCaseJ4.getFile(getSolrConfigFile()).toPath(), f);
+      f = confDir.toPath().resolve("schema.xml");
+      Files.copy(SolrTestCaseJ4.getFile(getSchemaFile()).toPath(), f);
       Files.createFile(homeDir.toPath().resolve("collection1/core.properties"));
     }
 
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
index bfe2f3dbd68..67cb3867043 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrClient.java
@@ -20,13 +20,13 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import org.apache.commons.io.FileUtils;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.lucene.util.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
@@ -300,12 +300,13 @@ public class TestLBHttpSolrClient extends SolrTestCaseJ4 {
       dataDir.mkdirs();
       confDir.mkdirs();
 
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrXmlFile()), new File(homeDir, "solr.xml"));
+      Files.copy(
+          SolrTestCaseJ4.getFile(getSolrXmlFile()).toPath(), homeDir.toPath().resolve("solr.xml"));
 
-      File f = new File(confDir, "solrconfig.xml");
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrConfigFile()), f);
-      f = new File(confDir, "schema.xml");
-      FileUtils.copyFile(SolrTestCaseJ4.getFile(getSchemaFile()), f);
+      Path f = confDir.toPath().resolve("solrconfig.xml");
+      Files.copy(SolrTestCaseJ4.getFile(getSolrConfigFile()).toPath(), f);
+      f = confDir.toPath().resolve("schema.xml");
+      Files.copy(SolrTestCaseJ4.getFile(getSchemaFile()).toPath(), f);
       Files.createFile(homeDir.toPath().resolve("collection1/core.properties"));
     }
 
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
index eb2470fa4d8..a2feae3f5ab 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
@@ -34,7 +34,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.SolrJettyTestBase;
 import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
 import org.apache.solr.client.solrj.impl.BaseHttpSolrClient;
@@ -320,7 +319,7 @@ public class TestSolrJErrorHandling extends SolrJettyTestBase {
       }
     }
 
-    String rbody = IOUtils.toString(is, StandardCharsets.UTF_8);
+    String rbody = new String(is.readAllBytes(), StandardCharsets.UTF_8);
     log.info("RESPONSE BODY:{}", rbody);
   }
 
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java
index 7388211fec5..20b651e4f9f 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java
@@ -17,15 +17,15 @@
 package org.apache.solr.client.solrj.embedded;
 
 import java.io.File;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.Locale;
 import java.util.Random;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.Header;
 import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.solr.SolrJettyTestBase;
 import org.apache.solr.SolrTestCaseJ4;
@@ -93,15 +93,17 @@ public class JettyWebappTest extends SolrTestCaseJ4 {
     // sure they compile ok
 
     String adminPath = "http://127.0.0.1:" + port + context + "/";
-    byte[] bytes = IOUtils.toByteArray(new URL(adminPath).openStream());
-    assertNotNull(bytes); // real error will be an exception
+    try (InputStream is = new URL(adminPath).openStream()) {
+      assertNotNull(is.readAllBytes()); // real error will be an exception
+    }
 
-    HttpClient client = HttpClients.createDefault();
-    HttpRequestBase m = new HttpGet(adminPath);
-    HttpResponse response = client.execute(m, HttpClientUtil.createNewHttpClientRequestContext());
-    assertEquals(200, response.getStatusLine().getStatusCode());
-    Header header = response.getFirstHeader("X-Frame-Options");
-    assertEquals("DENY", header.getValue().toUpperCase(Locale.ROOT));
-    m.releaseConnection();
+    try (CloseableHttpClient client = HttpClients.createDefault()) {
+      HttpRequestBase m = new HttpGet(adminPath);
+      HttpResponse response = client.execute(m, HttpClientUtil.createNewHttpClientRequestContext());
+      assertEquals(200, response.getStatusLine().getStatusCode());
+      Header header = response.getFirstHeader("X-Frame-Options");
+      assertEquals("DENY", header.getValue().toUpperCase(Locale.ROOT));
+      m.releaseConnection();
+    }
   }
 }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClientUtilTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClientUtilTest.java
index 0de3c7617c6..928d1e319b5 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClientUtilTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClientUtilTest.java
@@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets;
 import java.util.zip.GZIPOutputStream;
 import java.util.zip.ZipException;
 import javax.net.ssl.HostnameVerifier;
-import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
@@ -129,7 +128,7 @@ public class HttpClientUtilTest extends SolrTestCase {
   public void testNonRepeatableMalformedGzipEntityAutoClosed() throws IOException {
     HttpEntity baseEntity =
         new InputStreamEntity(
-            IOUtils.toInputStream("this is not compressed", StandardCharsets.UTF_8));
+            new ByteArrayInputStream("this is not compressed".getBytes(StandardCharsets.UTF_8)));
     HttpClientUtil.GzipDecompressingEntity gzipDecompressingEntity =
         new HttpClientUtil.GzipDecompressingEntity(baseEntity);
     Throwable error =
@@ -180,7 +179,7 @@ public class HttpClientUtilTest extends SolrTestCase {
     String testString = "this is compressed";
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
-      IOUtils.write(testString, gzipOutputStream, StandardCharsets.UTF_8);
+      gzipOutputStream.write(testString.getBytes(StandardCharsets.UTF_8));
     }
     // Use an ByteArrayEntity because it is repeatable
     HttpEntity baseEntity = new ByteArrayEntity(baos.toByteArray());
@@ -190,13 +189,13 @@ public class HttpClientUtilTest extends SolrTestCase {
       assertEquals(
           "Entity incorrect after decompression",
           testString,
-          IOUtils.toString(stream, StandardCharsets.UTF_8));
+          new String(stream.readAllBytes(), StandardCharsets.UTF_8));
     }
     try (InputStream stream = gzipDecompressingEntity.getContent()) {
       assertEquals(
           "Entity incorrect after decompression after repeating",
           testString,
-          IOUtils.toString(stream, StandardCharsets.UTF_8));
+          new String(stream.readAllBytes(), StandardCharsets.UTF_8));
     }
   }
 
@@ -205,7 +204,7 @@ public class HttpClientUtilTest extends SolrTestCase {
     String testString = "this is compressed";
     ByteArrayOutputStream baos = new ByteArrayOutputStream();
     try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
-      IOUtils.write(testString, gzipOutputStream, StandardCharsets.UTF_8);
+      gzipOutputStream.write(testString.getBytes(StandardCharsets.UTF_8));
     }
     // Use an InputStreamEntity because it is non-repeatable
     HttpEntity baseEntity = new InputStreamEntity(new ByteArrayInputStream(baos.toByteArray()));
@@ -215,7 +214,7 @@ public class HttpClientUtilTest extends SolrTestCase {
       assertEquals(
           "Entity incorrect after decompression",
           testString,
-          IOUtils.toString(stream, StandardCharsets.UTF_8));
+          new String(stream.readAllBytes(), StandardCharsets.UTF_8));
     }
     try (InputStream stream = gzipDecompressingEntity.getContent()) {
       expectThrows(
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
index d09eb907f9a..4cb7789e4ff 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/response/NoOpResponseParserTest.java
@@ -16,15 +16,13 @@
  */
 package org.apache.solr.client.solrj.response;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.io.StringReader;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.ReaderInputStream;
 import org.apache.solr.SolrJettyTestBase;
 import org.apache.solr.client.solrj.ResponseParser;
 import org.apache.solr.client.solrj.SolrClient;
@@ -49,8 +47,8 @@ import org.junit.Test;
  */
 public class NoOpResponseParserTest extends SolrJettyTestBase {
 
-  private static InputStream getResponse() throws IOException {
-    return new ReaderInputStream(new StringReader("NO-OP test response"), StandardCharsets.UTF_8);
+  private static InputStream getResponse() {
+    return new ByteArrayInputStream("NO-OP test response".getBytes(StandardCharsets.UTF_8));
   }
 
   @BeforeClass
@@ -87,7 +85,8 @@ public class NoOpResponseParserTest extends SolrJettyTestBase {
   private void assertResponse(String responseString) throws IOException {
     ResponseParser xmlResponseParser = new XMLResponseParser();
     NamedList<?> expectedResponse =
-        xmlResponseParser.processResponse(IOUtils.toInputStream(responseString, "UTF-8"), "UTF-8");
+        xmlResponseParser.processResponse(
+            new ByteArrayInputStream(responseString.getBytes(StandardCharsets.UTF_8)), "UTF-8");
     @SuppressWarnings({"unchecked"})
     List<SolrDocument> documentList =
         (List<SolrDocument>) expectedResponse.getAll("response").get(0);
@@ -105,7 +104,7 @@ public class NoOpResponseParserTest extends SolrJettyTestBase {
       Reader in = new InputStreamReader(is, StandardCharsets.UTF_8);
       NamedList<Object> response = parser.processResponse(in);
       assertNotNull(response.get("response"));
-      String expectedResponse = IOUtils.toString(getResponse(), "UTF-8");
+      String expectedResponse = new String(getResponse().readAllBytes(), StandardCharsets.UTF_8);
       assertEquals(expectedResponse, response.get("response"));
     }
   }
@@ -119,7 +118,7 @@ public class NoOpResponseParserTest extends SolrJettyTestBase {
       NamedList<Object> response = parser.processResponse(is, "UTF-8");
 
       assertNotNull(response.get("response"));
-      String expectedResponse = IOUtils.toString(getResponse(), "UTF-8");
+      String expectedResponse = new String(getResponse().readAllBytes(), StandardCharsets.UTF_8);
       assertEquals(expectedResponse, response.get("response"));
     }
   }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java b/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
index 5bb812a413f..eea00be5608 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/response/TestDelegationTokenResponse.java
@@ -17,9 +17,10 @@
 
 package org.apache.solr.client.solrj.response;
 
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.Map;
-import org.apache.commons.io.IOUtils;
 import org.apache.solr.SolrTestCase;
 import org.apache.solr.client.solrj.ResponseParser;
 import org.apache.solr.client.solrj.request.DelegationTokenRequest;
@@ -35,7 +36,8 @@ public class TestDelegationTokenResponse extends SolrTestCase {
       throws Exception {
     ResponseParser parser = request.getResponseParser();
     response.setResponse(
-        parser.processResponse(IOUtils.toInputStream(responseBody, "UTF-8"), "UTF-8"));
+        parser.processResponse(
+            new ByteArrayInputStream(responseBody.getBytes(StandardCharsets.UTF_8)), "UTF-8"));
   }
 
   private String getNestedMapJson(String outerKey, String innerKey, Object innerValue) {
diff --git a/solr/solrj/src/test/org/apache/solr/common/util/ContentStreamTest.java b/solr/solrj/src/test/org/apache/solr/common/util/ContentStreamTest.java
index f0a50f7dd41..6721358a0bd 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/ContentStreamTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/ContentStreamTest.java
@@ -39,7 +39,7 @@ public class ContentStreamTest extends SolrTestCaseJ4 {
     String input = "aads ghaskdgasgldj asl sadg ajdsg &jag # @ hjsakg hsakdg hjkas s";
     ContentStreamBase stream = new ContentStreamBase.StringStream(input);
     assertEquals(input.length(), stream.getSize().longValue());
-    assertEquals(input, IOUtils.toString(stream.getStream(), StandardCharsets.UTF_8));
+    assertEquals(input, new String(stream.getStream().readAllBytes(), StandardCharsets.UTF_8));
     assertEquals(input, IOUtils.toString(stream.getReader()));
   }
 
diff --git a/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java b/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
index 9ce1b6a2f14..c10afef30fa 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
@@ -31,7 +31,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.tests.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.EnumFieldValue;
@@ -256,21 +255,17 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
         ByteArrayOutputStream os = new ByteArrayOutputStream()) {
 
       Object data = generateAllDataTypes();
-      try {
-        javabin.marshal(data, os);
-        byte[] newFormatBytes = os.toByteArray();
-
-        InputStream is = getClass().getResourceAsStream(SOLRJ_JAVABIN_BACKCOMPAT_BIN);
-        byte[] currentFormatBytes = IOUtils.toByteArray(is);
+      javabin.marshal(data, os);
+      byte[] newFormatBytes = os.toByteArray();
 
+      try (InputStream is = getClass().getResourceAsStream(SOLRJ_JAVABIN_BACKCOMPAT_BIN)) {
+        assertNotNull(is);
+        byte[] currentFormatBytes = is.readAllBytes();
         for (int i = 1;
             i < currentFormatBytes.length;
             i++) { // ignore the first byte. It is version information
           assertEquals(newFormatBytes[i], currentFormatBytes[i]);
         }
-
-      } catch (IOException e) {
-        throw e;
       }
     }
   }
@@ -283,15 +278,16 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
       javabin.marshal(sdoc, os);
       byte[] newFormatBytes = os.toByteArray();
 
-      InputStream is = getClass().getResourceAsStream(SOLRJ_JAVABIN_BACKCOMPAT_BIN_CHILD_DOCS);
-      byte[] currentFormatBytes = IOUtils.toByteArray(is);
+      try (InputStream is =
+          getClass().getResourceAsStream(SOLRJ_JAVABIN_BACKCOMPAT_BIN_CHILD_DOCS)) {
+        assertNotNull(is);
+        byte[] currentFormatBytes = is.readAllBytes();
 
-      // ignore the first byte. It is version information
-      for (int i = 1; i < currentFormatBytes.length; i++) {
-        assertEquals(newFormatBytes[i], currentFormatBytes[i]);
+        // ignore the first byte. It is version information
+        for (int i = 1; i < currentFormatBytes.length; i++) {
+          assertEquals(newFormatBytes[i], currentFormatBytes[i]);
+        }
       }
-    } catch (IOException e) {
-      throw e;
     }
   }
 
diff --git a/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java b/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java
index 9711945237c..acc0a27c5eb 100644
--- a/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java
@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
 import java.lang.invoke.MethodHandles;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -1274,7 +1275,10 @@ public abstract class BaseDistributedSearchTestCase extends SolrTestCaseJ4 {
     FileUtils.copyDirectory(new File(getSolrHome()), jettyHome);
     String solrxml = getSolrXml();
     if (solrxml != null) {
-      FileUtils.copyFile(new File(getSolrHome(), solrxml), new File(jettyHome, "solr.xml"));
+      Files.copy(
+          Path.of(getSolrHome(), solrxml),
+          jettyHome.toPath().resolve("solr.xml"),
+          StandardCopyOption.REPLACE_EXISTING);
     }
   }
 
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index 5babe702154..b04fa944483 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -81,7 +81,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 import javax.xml.xpath.XPathExpressionException;
-import org.apache.commons.io.IOUtils;
 import org.apache.http.client.HttpClient;
 import org.apache.logging.log4j.Level;
 import org.apache.lucene.index.IndexWriterConfig;
@@ -119,6 +118,7 @@ import org.apache.solr.common.params.UpdateParams;
 import org.apache.solr.common.util.ContentStream;
 import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.IOUtils;
 import org.apache.solr.common.util.ObjectReleaseTracker;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.SuppressForbidden;
diff --git a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
index e63735e6580..27d3052e74a 100644
--- a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
+++ b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
@@ -21,6 +21,7 @@ import com.codahale.metrics.MetricFilter;
 import com.codahale.metrics.MetricRegistry;
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.lang.invoke.MethodHandles;
 import java.net.BindException;
@@ -53,7 +54,6 @@ import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.output.NullPrintStream;
 import org.apache.lucene.util.Constants;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.cloud.SocketProxy;
@@ -745,7 +745,7 @@ public class JettySolrRunner {
         MetricRegistry metricsRegisty = metricsManager.registry(registryName);
         try (PrintStream ps =
             outputDirectory == null
-                ? new NullPrintStream()
+                ? new PrintStream(OutputStream.nullOutputStream(), false, StandardCharsets.UTF_8)
                 : new PrintStream(
                     new File(outputDirectory, registryName + "_" + fileName),
                     StandardCharsets.UTF_8)) {
diff --git a/solr/test-framework/src/java/org/apache/solr/handler/BackupRestoreUtils.java b/solr/test-framework/src/java/org/apache/solr/handler/BackupRestoreUtils.java
index 0b79325eb9c..10456e4984e 100644
--- a/solr/test-framework/src/java/org/apache/solr/handler/BackupRestoreUtils.java
+++ b/solr/test-framework/src/java/org/apache/solr/handler/BackupRestoreUtils.java
@@ -25,7 +25,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-import org.apache.commons.io.IOUtils;
 import org.apache.lucene.tests.util.TestUtil;
 import org.apache.solr.SolrTestCase;
 import org.apache.solr.client.solrj.SolrClient;
@@ -110,13 +109,9 @@ public class BackupRestoreUtils extends SolrTestCase {
   }
 
   static void executeHttpRequest(String requestUrl) throws IOException {
-    InputStream stream = null;
-    try {
-      URL url = new URL(requestUrl);
-      stream = url.openStream();
-      stream.close();
-    } finally {
-      IOUtils.closeQuietly(stream);
+    URL url = new URL(requestUrl);
+    try (InputStream stream = url.openStream()) {
+      assert stream != null;
     }
   }
 }
diff --git a/solr/test-framework/src/java/org/apache/solr/handler/TestRestoreCoreUtil.java b/solr/test-framework/src/java/org/apache/solr/handler/TestRestoreCoreUtil.java
index 477dfd153b1..de275b8ec94 100644
--- a/solr/test-framework/src/java/org/apache/solr/handler/TestRestoreCoreUtil.java
+++ b/solr/test-framework/src/java/org/apache/solr/handler/TestRestoreCoreUtil.java
@@ -19,9 +19,9 @@ package org.apache.solr.handler;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import org.apache.commons.io.IOUtils;
 import org.junit.Assert;
 
 public class TestRestoreCoreUtil {
@@ -35,11 +35,9 @@ public class TestRestoreCoreUtil {
             + ReplicationHandler.CMD_RESTORE_STATUS;
     final Pattern pException = Pattern.compile("<str name=\"exception\">(.*?)</str>");
 
-    InputStream stream = null;
-    try {
-      URL url = new URL(leaderUrl);
-      stream = url.openStream();
-      String response = IOUtils.toString(stream, "UTF-8");
+    URL url = new URL(leaderUrl);
+    try (InputStream stream = url.openStream()) {
+      String response = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
       Matcher matcher = pException.matcher(response);
       if (matcher.find()) {
         Assert.fail("Failed to complete restore action with exception " + matcher.group(1));
@@ -49,9 +47,6 @@ public class TestRestoreCoreUtil {
       } else if (response.contains("<str name=\"status\">failed</str>")) {
         Assert.fail("Restore Failed");
       }
-      stream.close();
-    } finally {
-      IOUtils.closeQuietly(stream);
     }
     return false;
   }