Skip to content

Commit a4d60d7

Browse files
committed
fix spark-shell NPE without explicit -usejavacp
1 parent 6bba551 commit a4d60d7

File tree

4 files changed

+24
-19
lines changed

4 files changed

+24
-19
lines changed

bin/spark-shell

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ export _SPARK_CMD_USAGE="Usage: ./bin/spark-shell [options]
3737
Scala REPL options, Spark Classic only:
3838
-I <file> preload <file>, enforcing line-by-line interpretation"
3939

40-
# SPARK-4161: scala does not assume use of the java classpath,
41-
# so we need to add the "-Dscala.usejavacp=true" flag manually. We
42-
# do this specifically for the Spark shell because the scala REPL
43-
# has its own class loader, and any additional classpath specified
44-
# through spark.driver.extraClassPath is not automatically propagated.
45-
SPARK_SUBMIT_OPTS="$SPARK_SUBMIT_OPTS -Dscala.usejavacp=true"
46-
4740
function main() {
4841
export SPARK_SCALA_SHELL=1
4942
# In case of Spark Connect shell, the main class (and resource) is replaced in

bin/spark-shell2.cmd

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,5 @@ set _SPARK_CMD_USAGE=Usage: .\bin\spark-shell.cmd [options]^%LF%%LF%^%LF%%LF%^
2828
Scala REPL options:^%LF%%LF%^
2929
-I ^<file^> preload ^<file^>, enforcing line-by-line interpretation
3030

31-
rem SPARK-4161: scala does not assume use of the java classpath,
32-
rem so we need to add the "-Dscala.usejavacp=true" flag manually. We
33-
rem do this specifically for the Spark shell because the scala REPL
34-
rem has its own class loader, and any additional classpath specified
35-
rem through spark.driver.extraClassPath is not automatically propagated.
36-
if "x%SPARK_SUBMIT_OPTS%"=="x" (
37-
set SPARK_SUBMIT_OPTS=-Dscala.usejavacp=true
38-
goto run_shell
39-
)
40-
set SPARK_SUBMIT_OPTS="%SPARK_SUBMIT_OPTS% -Dscala.usejavacp=true"
41-
4231
:run_shell
4332
"%SPARK_HOME%\bin\spark-submit2.cmd" --class org.apache.spark.repl.Main --name "Spark shell" %*

repl/src/main/scala/org/apache/spark/repl/Main.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ object Main extends Logging {
6565
// Visible for testing
6666
private[repl] def doMain(args: Array[String], _interp: SparkILoop): Unit = {
6767
interp = _interp
68-
val jars = Utils
68+
val userJars = Utils
6969
.getLocalUserJarsForShell(conf)
7070
// Remove file:///, file:// or file:/ scheme if exists for each jar
7171
.map { x =>
7272
if (x.startsWith("file:")) new File(new URI(x)).getPath else x
7373
}
7474
.mkString(File.pathSeparator)
75+
val jvmClasspath = sys.props.getOrElse("java.class.path", "")
76+
val jars = Seq(userJars, jvmClasspath).filter(_.nonEmpty).mkString(File.pathSeparator)
7577
val interpArguments = List(
7678
"-Yrepl-class-based",
7779
"-Yrepl-outdir",

repl/src/test/scala/org/apache/spark/repl/ReplSuite.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,27 @@ class ReplSuite extends SparkFunSuite {
7272
def runInterpreterInPasteMode(master: String, input: String): String =
7373
runInterpreter(master, ":paste\n" + input + 4.toChar) // 4 is the ascii code of CTRL + D
7474

75+
test("SPARK-56447: spark-shell REPL initializes without explicit -classpath argument") {
76+
// Regression test for SPARK-56447: doMain must include java.class.path in the REPL
77+
// classpath even when the caller does not pass -classpath explicitly. Before the fix,
78+
// the Scala compiler mirror failed to find `object scala` because the JVM classpath
79+
// was not propagated to the REPL settings.
80+
// spark.repl.local.jars is not set, so userJars is intentionally empty;
81+
// the classpath must be derived from java.class.path alone.
82+
Main.sparkContext = null
83+
Main.sparkSession = null
84+
Main.conf.set("spark.master", "local")
85+
86+
val in = new BufferedReader(new StringReader("spark.version\n"))
87+
val out = new StringWriter()
88+
Main.doMain(Array.empty, new SparkILoop(in, new PrintWriter(out)))
89+
90+
val output = out.toString
91+
assertDoesNotContain("object scala in compiler mirror not found", output)
92+
assertDoesNotContain("Failed to initialize compiler", output)
93+
assertContains("res0: String =", output)
94+
}
95+
7596
def assertContains(message: String, output: String): Unit = {
7697
val isContain = output.contains(message)
7798
assert(isContain,

0 commit comments

Comments
 (0)