spark java lambda_java.lang.ClassCastException在远程服务器上的spark作业中使用lambda表达式...

你在这里有一个掩盖原始错误的后续错误.

当lambda实例被序列化时,他们使用writeReplace来解析它们的JRE特定

实施从持续的形式是一个SerializedLambda

实例.当SerializedLambda实例被还原时,它的readResolve方法将被调用

重建适当的lambda实例.正如文档所说,它将通过调用定义原始lambda的类的特殊方法(参见this answer)来实现.重要的一点是,原来的课程是需要的,这就是你的情况中缺少的东西.

但是有一个…特殊的… ObjectInputStream的行为.当它遇到异常时,它不会立即缓解.它将记录异常并继续该过程,标记当前正在读取的所有对象,因此取决于错误的对象也是错误的.只有在进程结束时才会抛出它遇到的原始异常.令它如此奇怪的是,它也将继续尝试设置这些对象的字段.但是当您查看ObjectInputStream.readOrdinaryObject行1806方法时:

if (obj != null &&

handles.lookupException(passHandle) == null &&

desc.hasReadResolveMethod())

{

Object rep = desc.invokeReadResolve(obj);

if (unshared && rep.getClass().isArray()) {

rep = cloneArray(rep);

}

if (rep != obj) {

handles.setObject(passHandle, obj = rep);

}

}

return obj;

}

您会发现在lookupException报告非空异常时,它不会调用readResolve方法.但是当替代没有发生时,继续尝试设置引用来源的字段值并不是一个好主意,但这正是在这里发生的,从而产生一个ClassCastException.

您可以轻松地重现问题:

public class Holder implements Serializable {

Runnable r;

}

public class Defining {

public static Holder get() {

final Holder holder = new Holder();

holder.r=(Runnable&Serializable)()->{};

return holder;

}

}

public class Writing {

static final File f=new File(System.getProperty("java.io.tmpdir"), "x.ser");

public static void main(String... arg) throws IOException {

try(FileOutputStream os=new FileOutputStream(f);

ObjectOutputStream oos=new ObjectOutputStream(os)) {

oos.writeObject(Defining.get());

}

System.out.println("written to "+f);

}

}

public class Reading {

static final File f=new File(System.getProperty("java.io.tmpdir"), "x.ser");

public static void main(String... arg) throws IOException, ClassNotFoundException {

try(FileInputStream is=new FileInputStream(f);

ObjectInputStream ois=new ObjectInputStream(is)) {

Holder h=(Holder)ois.readObject();

System.out.println(h.r);

h.r.run();

}

System.out.println("read from "+f);

}

}

编译这四个类,并运行写作.然后删除类文件Defining.class并运行阅读.然后你会得到一个

Exception in thread "main" java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field test.Holder.r of type java.lang.Runnable in instance of test.Holder

at java.io.ObjectStreamClass$FieldReflector.setObjFieldValues(ObjectStreamClass.java:2089)

at java.io.ObjectStreamClass.setObjFieldValues(ObjectStreamClass.java:1261)

(测试1.8.0_20)

最基本的一点是,一旦知道发生了什么,您可能会忘记这个序列化问题,解决问题所需要做的只是确保定义lambda表达式的类在lambda的运行时也可用反序列化.

Spark作业直接从IDE运行的示例(spark-submit默认分发jar):

SparkConf sconf = new SparkConf()

.set("spark.eventLog.dir", "hdfs://nn:8020/user/spark/applicationHistory")

.set("spark.eventLog.enabled", "true")

.setJars(new String[]{"/path/to/jar/with/your/class.jar"})

.setMaster("spark://spark.standalone.uri:7077");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值