kryo.readObject导致与ArrayList的NullPointerException

时间:2014-05-30 20:20:08

标签: java kryo

当我使用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,而其中一个字段未初始化导致异常。

文档说首先应该调用no参数构造函数,如果没有,可以使用StdInstantiatorStrategy来进行字段初始化。

我做错了什么?

4 个答案:

答案 0 :(得分:12)

使用kryo 2.24版,调用

kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());

覆盖使用class no argument构造函数的默认实例化器策略(如果存在)。正确的方法是致电:

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

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

我认为自2.21版以来这已经发生了变化

答案 1 :(得分:1)

我收到类似的空指针异常,我需要添加一个自定义序列化程序:https://github.com/magro/kryo-serializers

例如:

kryo.register( Collections.EMPTY_LIST.getClass(), new CollectionsEmptyListSerializer() );

答案 2 :(得分:1)

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

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

创建您自己的名为 MyKryoRegistrator 的 kryo 注册器工具

class MyKryoRegistrator extends KryoRegistrator {
  override def registerClasses(kryo: Kryo): Unit = {
    kryo.register(classOf[YourProtobufObject], new ProtobufSerializer())
  }
}
  • 第三,再次运行您的 Spark 作业,一切都会好起来的。

答案 3 :(得分:0)

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

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

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