From fe54790168ff39aad6211b9a5426089d3606cf74 Mon Sep 17 00:00:00 2001 From: Kousuke Saruta Date: Fri, 8 May 2026 04:46:32 +0900 Subject: [PATCH 1/3] Fix percent-encoding issue in SparkTestUtils classpath handling Replace URL.getFile() with new File(url.toURI).getPath in SparkTestUtils.scala to correctly handle classpath URLs containing percent-encoded characters (e.g., spaces encoded as %20). URL.getFile() returns percent-encoded strings, so paths containing spaces or special characters are not resolved correctly when passed to File constructors or compiler classpath arguments. Using url.toURI properly decodes the path. Four call sites are fixed: - createCompiledClass - createJarWithJavaSources - createJarWithScalaSources - expandManifestClasspath --- .../scala/org/apache/spark/util/SparkTestUtils.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala b/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala index fa5f99a1aae25..5c1652fa64612 100644 --- a/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala +++ b/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala @@ -53,8 +53,8 @@ private[spark] trait SparkTestUtils { Seq( "-classpath", classpathUrls - .map { - _.getFile + .map { u => + new File(u.toURI).getPath } .mkString(File.pathSeparator)) } else { @@ -123,7 +123,7 @@ private[spark] trait SparkTestUtils { val options = Seq("-d", classDir.getAbsolutePath) ++ ( if (classpathUrls.nonEmpty) { - Seq("-classpath", classpathUrls.map(_.getFile).mkString(File.pathSeparator)) + Seq("-classpath", classpathUrls.map(u => new File(u.toURI).getPath).mkString(File.pathSeparator)) } else Seq.empty ) @@ -177,7 +177,7 @@ private[spark] trait SparkTestUtils { // on Windows to work around CMD's command-line length limit and by some build/CI // tools. Expand any such JARs before invoking scalac so the classpath is complete. val expandedClasspath = classpathUrls.flatMap(expandManifestClasspath) - val cpStr = expandedClasspath.map(_.getFile).mkString(File.pathSeparator) + val cpStr = expandedClasspath.map(u => new File(u.toURI).getPath).mkString(File.pathSeparator) val args = Array("-classpath", cpStr, "-d", classDir.getAbsolutePath) ++ sourceFiles.map(_.getAbsolutePath) @@ -216,7 +216,7 @@ private[spark] trait SparkTestUtils { * original URL unchanged. */ private[spark] def expandManifestClasspath(url: URL): Seq[URL] = { - val file = new File(url.getFile) + val file = new File(url.toURI) if (!file.exists() || !file.getName.endsWith(".jar")) return Seq(url) try { val jarFile = new JarFile(file) From 63a795ac2497a913b6a5b4f40937c8f5b39a17c6 Mon Sep 17 00:00:00 2001 From: Kousuke Saruta Date: Wed, 27 May 2026 02:13:47 +0900 Subject: [PATCH 2/3] Add test for classpath handling with spaces in path --- .../spark/util/SparkTestUtilsSuite.scala | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 common/utils/src/test/scala/org/apache/spark/util/SparkTestUtilsSuite.scala diff --git a/common/utils/src/test/scala/org/apache/spark/util/SparkTestUtilsSuite.scala b/common/utils/src/test/scala/org/apache/spark/util/SparkTestUtilsSuite.scala new file mode 100644 index 0000000000000..10a599739f6cf --- /dev/null +++ b/common/utils/src/test/scala/org/apache/spark/util/SparkTestUtilsSuite.scala @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.spark.util + +import org.scalatest.funsuite.AnyFunSuite // scalastyle:ignore funsuite + +class SparkTestUtilsSuite extends AnyFunSuite with SparkTestUtils { // scalastyle:ignore funsuite + + test("SPARK-57081: createCompiledClass with spaces in classpath") { + val dir = SparkFileUtils.createTempDir(namePrefix = "path with spaces") + val sourceFile = new JavaSourceFromString("Hello", "public class Hello {}") + val result = createCompiledClass("Hello", dir, sourceFile, Seq(dir.toURI.toURL)) + assert(result.exists(), s"Compiled class file should exist at ${result.getPath}") + } +} From d42e403297466de7af581dfa1878407b1873c4cf Mon Sep 17 00:00:00 2001 From: Kousuke Saruta Date: Wed, 27 May 2026 04:09:40 +0900 Subject: [PATCH 3/3] Fix style --- .../src/main/scala/org/apache/spark/util/SparkTestUtils.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala b/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala index 5c1652fa64612..0af0e0f6de457 100644 --- a/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala +++ b/common/utils/src/main/scala/org/apache/spark/util/SparkTestUtils.scala @@ -123,7 +123,8 @@ private[spark] trait SparkTestUtils { val options = Seq("-d", classDir.getAbsolutePath) ++ ( if (classpathUrls.nonEmpty) { - Seq("-classpath", classpathUrls.map(u => new File(u.toURI).getPath).mkString(File.pathSeparator)) + Seq("-classpath", + classpathUrls.map(u => new File(u.toURI).getPath).mkString(File.pathSeparator)) } else Seq.empty )