调用目标异常。无法将 class X 转换为 class X。通过 spark-submit 在 Scala Imain 中调用时
InvocationTargetException. Cannot cast class X to class X. When invoked in Scala Imain through spark-submit
所以,我有以下用例。
我正在通过提供类似于 DSL 的界面来简化特定域的 Spark 数据帧的使用。
所有这些代码都放在由 maven shade 插件创建的 fat jar 中。 (fat jar = 没有 spark 和 hadoop 依赖项)
这个 fat jar 有一个 main class,我们称它为 JavaMain。
在 JavaMain 内部,我进行了一次 rest 调用以获取内容为有效 DSL 的字符串。
我用初始设置对象实例化了一个 IMain 对象。
我绑定了一些变量。使用 imain.bind 方法。
但是此绑定失败并出现以下错误:
Set failed in bind(results, com.dhruv.dsl.DslDataFrame.DSLResults, com.dhruv.dsl.DslDataFrame$DSLResults@7650a5f3)
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.callEither(IMain.scala:738)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:625)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:661)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:662)
at com.thoughtworks.dsl.DSL.run(DSL.scala:44)
at com.thoughtworks.dsl.JavaMain.run(JavaMain.java:30)
at com.thoughtworks.dsl.JavaMain.main(JavaMain.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:665)
at org.apache.spark.deploy.SparkSubmit$.doRunMain(SparkSubmit.scala:170)
at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:193)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:112)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassCastException: com.thoughtworks.dsl.DslDataFrame$DSLResults cannot be cast to com.thoughtworks.dsl.DslDataFrame$DSLResults
at $line3.$eval$.set(<console>:6)
at $line3.$eval.set(<console>)
... 21 more
更多上下文:
我在尝试这个时遇到了 classpath 的问题。虽然我好像没能全部解决。
之前在创建 Setting 对象时,我是这样做的:
val settings = {
val x = new Settings()
x.classpath.value += File.pathSeparator + System.getProperty("java.class.path")
x.usejavacp.value = true
x.verbose.value = true
x
}
然而,这似乎不起作用,因为在执行 spark 提交时,class 路径上只有 spark 和 hadoop 相关的 jar。
然后我将以下内容添加到 class路径中:
val urLs: Array[URL] = Thread.currentThread.getContextClassLoader.asInstanceOf[URLClassLoader].getURLs
并进行了以下操作:
val settings = {
val x = new Settings()
x.classpath.value += File.pathSeparator + urLs(0)
x.usejavacp.value = true
x.verbose.value = true
x
}
这是我用来绑定对象的代码:
interpreter.bind("notagin", new SomeDummyObject)
这引发了我之前附加的异常。
有趣的是,以下代码有效:(即在 Interpreter 中导入和新建同一对象不会导致问题)
interpreter.interpret(
"""
import com.dhruv.dsl.operations._
import com.dhruv.dsl.implicits._
import com.dhruv.dsl.DslDataFrame._
import org.apache.spark.sql.Column
import com.dhruv.dsl._
implicit def RichColumn(column: Column): RichColumn = new RichColumn(column)
val justdont = new SomeDummyObject()
justdont.justdontcallme(thatJson)
"""
)
我知道并困扰我的另一个细节是 IMain 在内部确实更改了 classloader。不确定这是否导致了问题。
非常感谢您的帮助。
好的。所以我们想出了解决问题的方法。
我认为 IMain 使用不同的类加载器来加载 类 而不是它们应该加载的类加载器。不管怎样,下面解决了这个问题,留给大家看看。
val interpreter = new IMain(settings){
override protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader
}
所以,我有以下用例。
我正在通过提供类似于 DSL 的界面来简化特定域的 Spark 数据帧的使用。 所有这些代码都放在由 maven shade 插件创建的 fat jar 中。 (fat jar = 没有 spark 和 hadoop 依赖项)
这个 fat jar 有一个 main class,我们称它为 JavaMain。
在 JavaMain 内部,我进行了一次 rest 调用以获取内容为有效 DSL 的字符串。
我用初始设置对象实例化了一个 IMain 对象。 我绑定了一些变量。使用 imain.bind 方法。
但是此绑定失败并出现以下错误:
Set failed in bind(results, com.dhruv.dsl.DslDataFrame.DSLResults, com.dhruv.dsl.DslDataFrame$DSLResults@7650a5f3)
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.callEither(IMain.scala:738)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:625)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:661)
at scala.tools.nsc.interpreter.IMain.bind(IMain.scala:662)
at com.thoughtworks.dsl.DSL.run(DSL.scala:44)
at com.thoughtworks.dsl.JavaMain.run(JavaMain.java:30)
at com.thoughtworks.dsl.JavaMain.main(JavaMain.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:665)
at org.apache.spark.deploy.SparkSubmit$.doRunMain(SparkSubmit.scala:170)
at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:193)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:112)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassCastException: com.thoughtworks.dsl.DslDataFrame$DSLResults cannot be cast to com.thoughtworks.dsl.DslDataFrame$DSLResults
at $line3.$eval$.set(<console>:6)
at $line3.$eval.set(<console>)
... 21 more
更多上下文:
我在尝试这个时遇到了 classpath 的问题。虽然我好像没能全部解决。
之前在创建 Setting 对象时,我是这样做的:
val settings = {
val x = new Settings()
x.classpath.value += File.pathSeparator + System.getProperty("java.class.path")
x.usejavacp.value = true
x.verbose.value = true
x
}
然而,这似乎不起作用,因为在执行 spark 提交时,class 路径上只有 spark 和 hadoop 相关的 jar。
然后我将以下内容添加到 class路径中:
val urLs: Array[URL] = Thread.currentThread.getContextClassLoader.asInstanceOf[URLClassLoader].getURLs
并进行了以下操作:
val settings = {
val x = new Settings()
x.classpath.value += File.pathSeparator + urLs(0)
x.usejavacp.value = true
x.verbose.value = true
x
}
这是我用来绑定对象的代码:
interpreter.bind("notagin", new SomeDummyObject)
这引发了我之前附加的异常。 有趣的是,以下代码有效:(即在 Interpreter 中导入和新建同一对象不会导致问题)
interpreter.interpret(
"""
import com.dhruv.dsl.operations._
import com.dhruv.dsl.implicits._
import com.dhruv.dsl.DslDataFrame._
import org.apache.spark.sql.Column
import com.dhruv.dsl._
implicit def RichColumn(column: Column): RichColumn = new RichColumn(column)
val justdont = new SomeDummyObject()
justdont.justdontcallme(thatJson)
"""
)
我知道并困扰我的另一个细节是 IMain 在内部确实更改了 classloader。不确定这是否导致了问题。
非常感谢您的帮助。
好的。所以我们想出了解决问题的方法。
我认为 IMain 使用不同的类加载器来加载 类 而不是它们应该加载的类加载器。不管怎样,下面解决了这个问题,留给大家看看。
val interpreter = new IMain(settings){
override protected def parentClassLoader: ClassLoader = this.getClass.getClassLoader
}