Крио-сериализация зависит от версии Java?

При десериализации сериализованного объекта (из файла) с помощью 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;
    }
}

person Tom    schedule 21.11.2015    source источник
comment
Трудно понять, как это сделать. Можете ли вы опубликовать десериализованный класс?   -  person user207421    schedule 22.11.2015
comment
Конечно - только что обновил пост   -  person Tom    schedule 22.11.2015
comment
У меня были те же проблемы с Kryo даже без обновления версии Java. Мы перешли на FST - он очень стабилен по сравнению с Kryo   -  person Jakub Kubrynski    schedule 23.11.2015
comment
Как выглядит ваш экземпляр kryo? Какой сериализатор вы использовали? Еще немного кода поможет.   -  person Christopher Schröder    schedule 23.11.2015


Ответы (1)


Kryo в целом нестабилен для разных JVM, если вы не очень осторожно при регистрации типов.

Когда Kryo встречает тип, которого он не видел, он увеличивает счетчик и регистрирует тип для этого значения. Он использует эти значения в графе объектов в качестве псевдонима для типа (оптимизация производительности). Если порядок выполнения на второй JVM немного отличается (независимо от того, совпадает ли версия с этой версией), то в Kryo будут разные реестры псевдонимов типов. Это предотвращает десериализацию сериализованных больших двоичных объектов.

Решение - включить в kryo «строгий» режим и вручную зарегистрировать классы с явными идентификаторами.

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

Это гарантирует, что классы будут зарегистрированы с одними и теми же стабильными идентификаторами на обеих JVM. Если вы это сделаете, вы сможете получить стабильную перекрестную сериализацию JVM.

Еще одна возможная проблема может заключаться в изменении полей класса до и после сериализации. Единственный практический способ справиться с изменением полей - использовать TaggedFieldSerializer

person Russell Cohen    schedule 30.11.2015