![](/img/trans.png)
[英]SBT gives java.lang.NullPointerException when trying to run simple “Hello!” example script
[英]SBT gives java.lang.NullPointerException when trying to run spark
我正在尝试在系统为 CentOs6 的 Linux 机器上使用 sbt 1.7.2 编译 spark。
当我尝试运行 clean 命令时:./build/ ./build/sbt clean
我得到以下输出:
java.lang.NullPointerException
at sun.net.util.URLUtil.urlNoFragString(URLUtil.java:50)
at sun.misc.URLClassPath.getLoader(URLClassPath.java:526)
at sun.misc.URLClassPath.getNextLoader(URLClassPath.java:498)
at sun.misc.URLClassPath.getResource(URLClassPath.java:252)
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
at java.lang.ClassLoader.loadClass(ClassLoader.java:406)
at java.lang.ClassLoader.loadClass(ClassLoader.java:406)
at java.lang.ClassLoader.loadClass(ClassLoader.java:406)
at java.lang.ClassLoader.loadClass(ClassLoader.java:406)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at sbt.internal.XMainConfiguration.run(XMainConfiguration.java:51)
at sbt.xMain.run(Main.scala:46)
at xsbt.boot.Launch$.$anonfun$run$1(Launch.scala:149)
at xsbt.boot.Launch$.withContextLoader(Launch.scala:176)
at xsbt.boot.Launch$.run(Launch.scala:149)
at xsbt.boot.Launch$.$anonfun$apply$1(Launch.scala:44)
at xsbt.boot.Launch$.launch(Launch.scala:159)
at xsbt.boot.Launch$.apply(Launch.scala:44)
at xsbt.boot.Launch$.apply(Launch.scala:21)
at xsbt.boot.Boot$.runImpl(Boot.scala:78)
at xsbt.boot.Boot$.run(Boot.scala:73)
at xsbt.boot.Boot$.main(Boot.scala:21)
at xsbt.boot.Boot.main(Boot.scala)
[error] [launcher] error during sbt launcher: java.lang.NullPointerException
当我使用 sbt 1.7.3 时也发生了,但是当我使用 sbt 1.6.2 时它可以成功清理和编译 spark。
我应该先检查什么? 我真的很感激任何人可以提供的任何建议。
一些关于如何调试 Spark 和 sbt 的建议。
克隆https://github.com/apache/spark ,在 IntelliJ 中打开它作为 sbt 项目。
在我可以在 IntelliJ 中运行我的代码之前,我必须执行sbt compile
并重新打开项目(之前我有一个错误object SqlBaseParser is not a member of package org.apache.spark.sql.catalyst.parser
)。 例如,我可以将以下对象放入sql/core/src/main/scala
并在 IntelliJ 中运行/调试它
// scalastyle:off
import org.apache.spark.sql.{Dataset, SparkSession}
object MyMain extends App {
val spark = SparkSession.builder()
.master("local")
.appName("SparkTestApp")
.getOrCreate()
case class Person(id: Long, name: String)
import spark.implicits._
val df: Dataset[Person] = spark.range(10).map(i => Person(i, i.toString))
df.show()
//+---+----+
//| id|name|
//+---+----+
//| 0| 0|
//| 1| 1|
//| 2| 2|
//| 3| 3|
//| 4| 4|
//| 5| 5|
//| 6| 6|
//| 7| 7|
//| 8| 8|
//| 9| 9|
//+---+----+
}
当这些弹出窗口出现时,我还按下了Run npm install
、 Load Maven project
,但我没有注意到其中的区别。
还有一次我不得不在sql/catalyst/target/scala-2.12/src_managed
中保留Project Structure
只有一个源根sql/catalyst/target/scala-2.12/src_managed/main
(而不是sql/catalyst/target/scala-2.12/src_managed/main/antlr4
)。 我有错误,例如SqlBaseLexer is already defined as class SqlBaseLexer
。
使用 IntelliJ IDEA 构建 Apache Spark 源代码: https ://yujheli-wordpress-com.translate.goog/2020/03/26/build-apache-spark-source-code-with-intellij-idea/?_x_tr_sl=auto&_x_tr_tl= en&_x_tr_hl=uk&_x_tr_pto=wapp (中文原文: https ://yujheli.wordpress.com/2020/03/26/build-apache-spark-source-code-with-intellij-idea/)
为什么构建 Spark 源会给出“object sbt is not a member of package com.typesafe”?
sbt 本身很棘手https://www.lihaoyi.com/post/SowhatswrongwithSBT.html并且构建它也有点棘手。
克隆https://github.com/sbt/sbt ,在 IntelliJ 中打开它。 让我们尝试使用这个克隆的 sbt 运行之前的 Spark 代码。
sbt 似乎不打算在指定目录中运行。 我将以下对象放在client/src/main/scala
object MyClient extends App {
System.setProperty("user.dir", "../spark")
sbt.client.Client.main(Array("sql/runMain MyMain"))
}
(通常,不建议改变系统属性user.dir
: How to use "cd" command using Java runtime? )
我必须首先执行sbt compile
(这包括命令sbt generateContrabands
--- sbt 使用 sbt 插件sbt-contraband
( ContrabandPlugin
, JsonCodecPlugin
),以前是sbt-datatype
,用于代码生成: https ://github.com/sbt/contraband https://www.scala-sbt.org/contraband/ https://www.scala-sbt.org/1.x/docs/Datatype.html https://github.com/eed3si9n/gigahorse/tree/develop /core/src/main/违禁品)。 我有错误not found: value ScalaKeywords
。
下一个错误是type ExcludeItem is not a member of package sbt.internal.bsp
。 您可以在protocol/src/main/contraband-scala/sbt/internal/bsp/codec
中删除文件ExcludeItemFormats.scala
、 ExcludesItemFormats.scala
、 ExcludesParamsFormats.scala
、 ExcludesResultFormats.scala
。 它们是过时的自动生成文件。 您可以检查是否删除目录protocol/src/main/contraband-scala
的内容(这是自动生成源的根)并执行sbt generateContrabands
除了这四个文件之外的所有文件都将被恢复。 由于某些原因,这些文件并没有混淆 sbt,而是混淆了 IntelliJ。
现在,在运行时, MyClient
产生
//[info] +---+----+
//[info] | id|name|
//[info] +---+----+
//[info] | 0| 0|
//[info] | 1| 1|
//[info] | 2| 2|
//[info] | 3| 3|
//[info] | 4| 4|
//[info] | 5| 5|
//[info] | 6| 6|
//[info] | 7| 7|
//[info] | 8| 8|
//[info] | 9| 9|
//[info] +---+----+
sbt.client.Client
被称为瘦客户端。 或者,您可以在本地发布它并作为依赖项使用
build.sbt ( https://github.com/sbt/sbt/blob/v1.8.0/build.sbt#L1160 )
lazy val sbtClientProj = (project in file("client"))
.enablePlugins(NativeImagePlugin)
.dependsOn(commandProj)
.settings(
commonBaseSettings,
scalaVersion := "2.12.11",
publish / skip := false, // change true to false
name := "sbt-client",
.......
sbt publishLocal
一个新项目:
构建.sbt
scalaVersion := "2.12.17"
// ~/.ivy2/local/org.scala-sbt/sbt-client/1.8.1-SNAPSHOT/jars/sbt-client.jar
libraryDependencies += "org.scala-sbt" % "sbt-client" % "1.8.1-SNAPSHOT"
源代码/main/scala/Main.scala
object Main extends App {
System.setProperty("user.dir", "../spark")
sbt.client.Client.main(Array("sql/runMain MyMain"))
//[info] +---+----+
//[info] | id|name|
//[info] +---+----+
//[info] | 0| 0|
//[info] | 1| 1|
//[info] | 2| 2|
//[info] | 3| 3|
//[info] | 4| 4|
//[info] | 5| 5|
//[info] | 6| 6|
//[info] | 7| 7|
//[info] | 8| 8|
//[info] | 9| 9|
//[info] +---+----+
}
但是瘦客户端不是 sbt 正常运行的方式。 堆栈跟踪中的sbt.xMain
来自https://github.com/sbt/sbt 。 它在这里: https ://github.com/sbt/sbt/blob/1.8.x/main/src/main/scala/sbt/Main.scala#L44 但是来自堆栈跟踪的xsbt.boot.Boot
不是来自这个repo,它来自https://github.com/sbt/launcher ,即https://github.com/sbt/launcher/blob/1.x/launcher-implementation/src/main/scala/xsbt/boot/Boot .scala
问题是 sbt 分两步运行。 sbt 可执行文件(通常从https://www.scala-sbt.org/download.html#universal-packages下载)是一个 shell 脚本,首先它运行sbt-launch.jar
(对象xsbt.boot.Boot
)
https://github.com/sbt/sbt/blob/v1.8.0/sbt#L507-L512
execRunner "$java_cmd" \
"${java_args[@]}" \
"${sbt_options[@]}" \
-jar "$sbt_jar" \
"${sbt_commands[@]}" \
"${residual_args[@]}"
其次,后者反射性地调用 sbt(类sbt.xMain
)
val main = appProvider.newMain()
try {
withContextLoader(appProvider.loader)(main.run(appConfig))
// implementation of the above appProvider.newMain()
else if (AppMainClass.isAssignableFrom(entryPoint)) mainClass.newInstance
// implementation of the above main.run(appConfig)
mainMethod.invoke(null, configuration.arguments).asInstanceOf[xsbti.Exit]
然后xMain#run
通过XMainConfiguration#run
反射调用xMain.run
https://github.com/sbt/sbt/blob/v1.8.0/main/src/main/scala/sbt/Main.scala#L44-L47
class xMain extends xsbti.AppMain {
def run(configuration: xsbti.AppConfiguration): xsbti.MainResult =
new XMainConfiguration().run("xMain", configuration)
}
Class<?> clazz = loader.loadClass("sbt." + moduleName + "$");
Object instance = clazz.getField("MODULE$").get(null);
Method runMethod = clazz.getMethod("run", xsbti.AppConfiguration.class);
try {
.....
return (xsbti.MainResult) runMethod.invoke(instance, updatedConfiguration);
然后它下载并运行必要版本的 Scala(在build.sbt
中指定)和其余 sbt 的必要版本(在project/build.properties
中指定)。
让我们为启动器考虑一个 helloworld。
启动器由一个库(接口)组成
https://mvnrepository.com/artifact/org.scala-sbt/launcher-interface
https://github.com/sbt/launcher/tree/1.x/launcher-interface
和启动器可运行的罐子
https://mvnrepository.com/artifact/org.scala-sbt/launcher
https://github.com/sbt/launcher/tree/1.x/launcher-implementation/src
创建一个项目(取决于编译时的启动器界面)
构建.sbt
lazy val root = (project in file("."))
.settings(
name := "scalademo",
organization := "com.example",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.13.10",
libraryDependencies ++= Seq(
"org.scala-sbt" % "launcher-interface" % "1.4.1" % Provided,
),
)
src/main/scala/mypackage/Main.scala (此类将是使用启动器时的入口点)
package mypackage
import xsbti.{AppConfiguration, AppMain, Exit, MainResult}
class Main extends AppMain {
def run(configuration: AppConfiguration): MainResult = {
val scalaVersion = configuration.provider.scalaProvider.version
println(s"Hello, World! Running Scala $scalaVersion")
configuration.arguments.foreach(println)
new Exit {
override val code: Int = 0
}
}
}
做sbt publishLocal
。 项目 jar 将发布在~/.ivy2/local/com.example/scalademo_2.13/0.1.0-SNAPSHOT/jars/scalademo_2.13.jar
下载启动器可运行 jar https://repo1.maven.org/maven2/org/scala-sbt/launcher/1.4.1/launcher-1.4.1.jar
创建启动器配置
我的应用程序配置
[scala]
version: 2.13.10
[app]
org: com.example
name: scalademo
version: 0.1.0-SNAPSHOT
class: mypackage.Main
cross-versioned: binary
[repositories]
local
maven-central
[boot]
directory: ${user.home}/.myapp/boot
然后命令java -jar launcher-1.4.1.jar @my.app.configuration abc
产生
//Hello world! Running Scala 2.13.10
//a
//b
//c
出现了文件
~/.myapp/boot/scala-2.13.10/com.example/scalademo/0.1.0-SNAPSHOT
scalademo_2.13.jar
scala-library-2.13.10.jar
~/.myapp/boot/scala-2.13.10/lib
java-diff-utils-4.12.jar
jna-5.9.0.jar
jline-3.21.0.jar
scala-library.jar
scala-compiler.jar
scala-reflect.jar
因此启动器有助于在仅安装 Java 的环境中运行应用程序(不需要 Scala),将使用 Ivy 依赖项解析。 有一些功能可以处理返回码、使用不同的 Scala 版本重启应用程序、启动服务器等。
或者,可以使用以下任何命令
java -Dsbt.boot.properties=my.app.configuration -jar launcher-1.4.1.jar
java -jar launcher-repacked.jar # put my.app.configuration to sbt/sbt.boot.properties/ and repack the jar
https://www.scala-sbt.org/1.x/docs/Launcher-Getting-Started.html
Sbt https://github.com/sbt/sbt使用 sbt 插件SbtLauncherPlugin
https://github.com/sbt/sbt/blob/v1.8.0/project/SbtLauncherPlugin.scala以便从原始启动器启动launcher
https://github.com/sbt/launcher/tree/1.x/launcher-implementation/src
https://mvnrepository.com/artifact/org.scala-sbt/launcher
它构建sbt-launch
https://github.com/sbt/sbt/tree/v1.8.0/launch
https://mvnrepository.com/artifact/org.scala-sbt/sbt-launch
基本上, sbt-launch
与launcher
的不同之处在于注入了默认配置sbt.boot.properties
。
如果我们想用启动器运行 sbt 那么我们应该找到一种方法来为 sbt 指定一个工作目录(类似于我们在使用瘦客户端时的做法)。
工作目录可以设置为 1) 在sbt.xMain
( sbt
) 中或 2) 在xsbt.boot.Boot
( sbt-launcher
) 中。
1)
使sbt.xMain
非最终的,以便它可以被扩展
/*final*/ class xMain extends xsbti.AppMain {
...........
https://github.com/sbt/sbt/blob/v1.8.0/main/src/main/scala/sbt/Main.scala#L44
将新类放入main/src/main/scala
(启动器样式的入口点)
import sbt.xMain
import xsbti.{ AppConfiguration, AppProvider, MainResult }
import java.io.File
class MyXMain extends xMain {
override def run(configuration: AppConfiguration): MainResult = {
val args = configuration.arguments
val (dir, rest) =
if (args.length >= 1 && args(0).startsWith("dir=")) {
(
Some(args(0).stripPrefix("dir=")),
args.drop(1)
)
} else {
(None, args)
}
dir.foreach { dir =>
System.setProperty("user.dir", dir)
}
// xMain.run(new AppConfiguration { // not ok
// new xMain().run(new AppConfiguration { // not ok
super[xMain].run(new AppConfiguration { // ok
override val arguments: Array[String] = rest
override val baseDirectory: File =
dir.map(new File(_)).getOrElse(configuration.baseDirectory)
override val provider: AppProvider = configuration.provider
})
}
}
sbt publishLocal
我的.sbt.configuration
[scala]
version: auto
#version: 2.12.17
[app]
org: org.scala-sbt
name: sbt
#name: main # not ok
version: 1.8.1-SNAPSHOT
class: MyXMain
#class: sbt.xMain
components: xsbti,extra
cross-versioned: false
#cross-versioned: binary
[repositories]
local
maven-central
[boot]
directory: ${user.home}/.mysbt/boot
[ivy]
ivy-home: ${user.home}/.ivy2
一个命令:
java -jar launcher-1.4.1.jar @my.sbt.configuration dir=/path_to_spark/spark "sql/runMain MyMain"
要么
java -jar sbt-launch.jar @my.sbt.configuration dir=/path_to_spark/spark "sql/runMain MyMain"
//[info] +---+----+
//[info] | id|name|
//[info] +---+----+
//[info] | 0| 0|
//[info] | 1| 1|
//[info] | 2| 2|
//[info] | 3| 3|
//[info] | 4| 4|
//[info] | 5| 5|
//[info] | 6| 6|
//[info] | 7| 7|
//[info] | 8| 8|
//[info] | 9| 9|
//[info] +---+----+
( sbt-launch.jar
取自~/.ivy2/local/org.scala-sbt/sbt-launch/1.8.1-SNAPSHOT/jars
或只是https://mvnrepository.com/artifact/org.scala-sbt /sbt-launch因为我们还没有修改启动器)
我必须从spark
复制scalastyle-config.xml
,否则找不到。
我仍然有fatal: Not a git repository (or any parent up to mount parent...) Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
2)
项目/Dependencies.scala ( https://github.com/sbt/sbt/blob/v1.8.0/project/Dependencies.scala#L25 )
val launcherVersion = "1.4.2-SNAPSHOT" // modified
克隆https://github.com/sbt/launcher并进行以下更改
build.sbt ( https://github.com/sbt/launcher/blob/v1.4.1/build.sbt#L11 )
ThisBuild / version := {
val orig = (ThisBuild / version).value
if (orig.endsWith("-SNAPSHOT")) "1.4.2-SNAPSHOT" // modified
else orig
}
启动器实现/src/main/scala/xsbt/boot/Launch.scala ( https://github.com/sbt/launcher/blob/v1.4.1/launcher-implementation/src/main/scala/xsbt/boot/启动.scala#L17 #L21 )
class LauncherArguments(
val args: List[String],
val isLocate: Boolean,
val isExportRt: Boolean,
val dir: Option[String] = None // added
)
object Launch {
def apply(arguments: LauncherArguments): Option[Int] =
apply((new File(arguments.dir.getOrElse(""))).getAbsoluteFile, arguments) // modified
.............
启动器实现/src/main/scala/xsbt/boot/Boot.scala ( https://github.com/sbt/launcher/blob/v1.4.1/launcher-implementation/src/main/scala/xsbt/boot/启动.scala#L41-L67 )
def parseArgs(args: Array[String]): LauncherArguments = {
@annotation.tailrec
def parse(
args: List[String],
isLocate: Boolean,
isExportRt: Boolean,
remaining: List[String],
dir: Option[String] // added
): LauncherArguments =
args match {
...................
case "--locate" :: rest => parse(rest, true, isExportRt, remaining, dir) // modified
case "--export-rt" :: rest => parse(rest, isLocate, true, remaining, dir) // modified
// added
case "--mydir" :: next :: rest => parse(rest, isLocate, isExportRt, remaining, Some(next))
case next :: rest => parse(rest, isLocate, isExportRt, next :: remaining, dir) // modified
case Nil => new LauncherArguments(remaining.reverse, isLocate, isExportRt, dir) // modified
}
parse(args.toList, false, false, Nil, None)
}
sbt 启动器: sbt publishLocal
sbt: sbt publishLocal
我的.sbt.configuration
[scala]
version: auto
[app]
org: org.scala-sbt
name: sbt
version: 1.8.1-SNAPSHOT
#class: MyXMain
class: sbt.xMain
components: xsbti,extra
cross-versioned: false
[repositories]
local
maven-central
[boot]
directory: ${user.home}/.mysbt/boot
[ivy]
ivy-home: ${user.home}/.ivy2
一个命令:
java -jar launcher-1.4.2-SNAPSHOT.jar @my.sbt.configuration --mydir /path_to_spark/spark "sql/runMain MyMain"
要么
java -jar sbt-launch.jar @my.sbt.configuration --mydir /path_to_spark/spark "sql/runMain MyMain"
要么
java -jar sbt-launch.jar --mydir /path_to_spark/spark "sql/runMain MyMain"
(使用默认sbt.boot.properties
而不是my.sbt.configuration
)
(我们正在使用修改后的launcher
或使用此修改后的launcher
器的新sbt-launch
)。
或者,我们可以在 IntelliJ 中的xsbt.boot.Boot
的“运行配置”中指定“程序参数”
@/path_to_sbt_config/my.sbt.configuration --mydir /path_to_spark/spark "sql/runMain MyMain"
也可以在 IntelliJ 的“运行配置”中指定工作目录/path_to_spark/spark
。 然后剩下的“程序参数”是
@/path_to_sbt_config/my.sbt.configuration "sql/runMain MyMain"
我尝试使用"org.scala-sbt" % "launcher" % "1.4.2-SNAPSHOT"
或"org.scala-sbt" % "sbt-launch" % "1.8.1-SNAPSHOT"
作为依赖但得到了No RuntimeVisibleAnnotations in classfile with ScalaSignature attribute: class Boot
。
因此,我们可以在 IntelliJ 中和/或使用println
运行/调试 sbt-launcher 代码,并使用println
运行/调试 sbt 代码(因为没有可运行的对象)。
从您的堆栈跟踪中我怀疑其中一个类加载器urls
为 null
https://github.com/openjdk/jdk/blob/jdk8-b120/jdk/src/share/classes/sun/misc/URLClassPath.java#L82
也许你可以添加到sbt.xMain#run
或MyXMain#run
类的东西
var cl = getClass.getClassLoader
while (cl != null) {
println(s"classloader: ${cl.getClass.getName}")
cl match {
case cl: URLClassLoader =>
println("classloader urls:")
cl.getURLs.foreach(println)
case _ =>
println("not URLClassLoader")
}
cl = cl.getParent
}
为了查看什么 url 为空。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.