11

当我使用 kryo 反序列化 ArrayList 对象时,我得到一个 NullPointerException。

Caused by: java.lang.NullPointerException   
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:215)   
at java.util.ArrayList.ensureCapacity(ArrayList.java:199)   
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:96)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:22)    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:679)     
at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)

我可以看到 StdInstantiatorStrategy 创建了一个 ArrayList 而没有调用其构造函数,而其中一个字段未初始化导致异常。

文档说应该首先调用无参数构造函数,如果没有可用的,则应该使用 StdInstantiatorStrategy 逐个字段进行初始化。

我究竟做错了什么?

4

4 回答 4

13

使用 kryo 2.24 版,调用

kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());

覆盖默认实例化策略,该策略使用类无参数构造函数(如果存在)。正确的方法是调用:

((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());

这在这里解释https://github.com/EsotericSoftware/kryo

我认为这自 2.21 版以来已经改变

于 2014-05-30T20:20:08.230 回答
1

I was getting a similar null pointer exception and I needed to add a custom serializer from: https://github.com/magro/kryo-serializers

Ex:

kryo.register( Collections.EMPTY_LIST.getClass(), new CollectionsEmptyListSerializer() );
于 2018-05-09T04:41:38.213 回答
1

我遇到了同样的问题,终于解决了。就我而言,我在 Spark 作业中使用 protobuf 对象。Spark kryo 序列化程序无法很好地序列化/反序列化 protobuf 对象。我们可以使用两种方法来解决这个问题。

  1. 使用 protobuf 默认的序列化/反序列化方法而不是 kryo 序列化方法。例如,您可以将 Spark 转换rdd[YourProtobufObject]rdd[ByteString],使用 pb.toByteString()进行序列化并使用.parseFrom(xxByteString)反序列化。实际上,这种方法并不优雅,但它确实有效。
  2. 将您自己的 protobuf 类注册到 kryo。详情如下。
  • 首先,将配置添加到SparkConf. 例如
conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
.set("spark.kryo.registrator","your.own.registrator.implement.MyKryoRegistrator")
  • 其次,创建您自己的注册器工具。你可以使用 Twitter 开源的 Chill 项目ProtobufSerializer依赖或者mvnrepositoryProtobufSerializer直接使用。maven 依赖项看起来像这样。

     <dependency>
         <groupId>com.twitter</groupId>
         <artifactId>chill_2.11</artifactId>
         <version>0.9.3</version>
     </dependency>
     <dependency>
         <groupId>com.twitter</groupId>
         <artifactId>chill-protobuf</artifactId>
         <version>0.9.3</version>
         <exclusions>
             <exclusion>
                 <groupId>com.twitter</groupId>
                 <artifactId>chill-java</artifactId>
             </exclusion>
         </exclusions>
     </dependency>
    

创建你自己的 kryo 注册器实现命名MyKryoRegistrator

class MyKryoRegistrator extends KryoRegistrator {
  override def registerClasses(kryo: Kryo): Unit = {
    kryo.register(classOf[YourProtobufObject], new ProtobufSerializer())
  }
}
  • 第三,再次运行您的 Spark 作业,就可以了。
于 2021-03-28T13:19:35.370 回答
0

还要注意如何创建列表,有一些方法可以创建不可修改的列表,这可能会导致这种序列化麻烦。

例如,测试中流行的快捷方式Arrays.asList("a", "b")可能会出现问题。

解决方法:new ArrayList<>(asList("a", "b"))

于 2020-04-28T13:48:48.663 回答