Kryo序列化依赖于Java版本?

时间:2015-11-21 20:21:33

标签: java serialization kryo

使用Kryo反序列化序列化对象(从文件)时,我得到以下异常:

java.lang.ExceptionInInitializerError
    (...)
Caused by: com.esotericsoftware.kryo.KryoException: (...)
Serialization trace: (...)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:125)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:786)
    at com.esotericsoftware.kryo.serializers.MapSerializer.read(MapSerializer.java:143)
    at com.esotericsoftware.kryo.serializers.MapSerializer.read(MapSerializer.java:21)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:682)
    (...)
Caused by: java.lang.IndexOutOfBoundsException: Index: 1582, Size: 2
    at java.util.ArrayList.rangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at com.esotericsoftware.kryo.util.MapReferenceResolver.getReadObject(MapReferenceResolver.java:42)
    at com.esotericsoftware.kryo.Kryo.readReferenceOrNull(Kryo.java:830)
    at com.esotericsoftware.kryo.Kryo.readObjectOrNull(Kryo.java:753)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:113)
    ... 27 more

我的假设是反序列化(即它改变了)时序列化格式没有被正确理解。 用于序列化和反序列化的Kryo版本是相同的。在序列化时,java版本可能有所不同:这可能是一个解释吗?

如果没有,关于我生成此类异常的任何其他提示都非常受欢迎!

非常感谢,托马斯

建议

更新:,特此是从文件中反序列化的类

反序列化的主要类是HashMap<Integer, PreflopEhsVO> 自定义类定义(子和父)是:

public class PreflopEhsVOExtended extends PreflopEhsVO{
    private int numbValues = 0;

    public synchronized void addValue(PreflopEhsVO values){
        if (numbValues == 0) this.valuesPerNumbOpp = values.valuesPerNumbOpp;
        else{
            //Weighted avg
            for (int i=0; i<this.valuesPerNumbOpp.length; ++i) this.valuesPerNumbOpp[i] = (this.valuesPerNumbOpp[i] * numbValues + values.valuesPerNumbOpp[i]) / (float) (numbValues + 1);
            ++numbValues;
        }
    }

    public PreflopEhsVOExtended(PreflopEhsVO values) {
        this.valuesPerNumbOpp = values.valuesPerNumbOpp;
        this.numbValues = 1;
    }
}

public class PreflopEhsVO {
    public float[] valuesPerNumbOpp = new float[9];

    public PreflopEhsVO(){
    }

    public PreflopEhsVO(float[] valuesPerNumbOpp) {
        this.valuesPerNumbOpp = valuesPerNumbOpp;
    }
}

1 个答案:

答案 0 :(得分:5)

Kryo一般来说在不同的JVM中不稳定,除非您非常小心关于如何注册类型。

当Kryo遇到一个类型时,它还没有看到它增加一个计数器并将该类型注册到该值。它使用对象图中的这些值作为类型的别名(性能优化)。如果第二个JVM上的执行顺序略有不同(无论版本是否相同),那么Kryo将最终使用不同类型的别名注册表。这可以防止序列化的blob被反序列化。

解决这个问题的方法是打开&#34; strict&#34; kryo中的模式并使用显式ids手动注册类。

  kryo.register(SomeClass.class, 1);
  kryo.register(AnotherClass.class, 2);

这将确保类在两个JVM上都注册到相同的稳定ID。如果这样做,您应该能够获得稳定的跨JVM序列化。

另一个可能的问题可能是类序列化前后字段的更改。处理更改字段的唯一实用方法是使用TaggedFieldSerializer