使用Kryo进行通用的Java序列化/反序列化

6
我正在尝试使用Kryo 2.19和默认序列化程序(FieldSerializer),将自定义类(例如SomeClass,具有默认无参构造函数)的对象序列化和反序列化为byte[]数组。 序列化似乎可以正常工作,但在反序列化时,根据SomeClass的实际实现,我会得到各种异常。 代码大致如下:
SomeClass object = getObject(); // Create and populate a new object of SomeClass

Kryo kryo = new Kryo();
FieldSerializer<?> serializer = new FieldSerializer<SomeClass>(kryo, SomeClass.class);
kryo.register(SomeClass.class, serializer);

ByteArrayOutputStream stream = new ByteArrayOutputStream();
Output output = new Output(stream);

kryo.writeObject(output, object);

output.close(); // Also calls output.flush()

byte[] buffer = stream.toByteArray(); // Serialization done, get bytes

// Deserialize the serialized object.
object = kryo.readObject(new Input(new ByteArrayInputStream(buffer)), SomeClass.class);

我收到的异常示例是:

An example of the exceptions I am getting is:

Exception in thread "main" java.lang.IncompatibleClassChangeError: Found interface org.objectweb.asm.MethodVisitor, but class was expected
    at com.esotericsoftware.reflectasm.ConstructorAccess.insertConstructor(ConstructorAccess.java:89)
    at com.esotericsoftware.reflectasm.ConstructorAccess.get(ConstructorAccess.java:70)
    at com.esotericsoftware.kryo.Kryo.newInstantiator(Kryo.java:1009)
    at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:1059)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.create(FieldSerializer.java:228)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:217)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:629)

似乎参数化类型在反序列化时存在问题。为了测试这一假设,这里提供了一个带参数化实现的SomeClassgetObject()函数:
class SomeClass<T extends Serializable>
{
    private final T[] elements;

    private final int first;
    private final int second;

    private SomeClass()
    {
        this.elements = null;
        this.first  = 0;
        this.second = 0;
    }

    private SomeClass(T[] elements, int first, int second)
    {
        this.elements = elements;
        this.first = first;
        this.second = second;
    }
}

SomeClass<?> getObject()
{
    String[] elements = new String[] {"This is a test", "one"};

    return new SomeClass<String>(elements, 1, 2);
}

这个序列化很好,但是反序列化会抛出以下异常(注意字符串的第一个字母在异常原因中未报告):
Exception in thread "main" com.esotericsoftware.kryo.KryoException: Unable to find class: his is a test
Serialization trace:
elements (net.cetas.parserserver.data.report.SourceDataReporter$SomeClass)
    at com.esotericsoftware.kryo.util.DefaultClassResolver.readName(DefaultClassResolver.java:132)
    at com.esotericsoftware.kryo.util.DefaultClassResolver.readClass(DefaultClassResolver.java:109)
    at com.esotericsoftware.kryo.Kryo.readClass(Kryo.java:613)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:724)
    at com.esotericsoftware.kryo.serializers.DefaultArraySerializers$ObjectArraySerializer.read(DefaultArraySerializers.java:338)
    at com.esotericsoftware.kryo.serializers.DefaultArraySerializers$ObjectArraySerializer.read(DefaultArraySerializers.java:293)
    at com.esotericsoftware.kryo.Kryo.readObjectOrNull(Kryo.java:702)
    at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.read(FieldSerializer.java:521)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:221)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:629)

如果上述类没有参数化实现(即,将elements数组声明为String[]),反序列化将按预期工作。
有任何想法吗?

1
你能在这里发布'SomeClass'的代码吗?我记得在Kryo中,您应该注册所有可以序列化的类(例如,如果您的类使用ArrayList,则也应该注册)。另一个问题是,它适用于故意简单的类吗? - Mark Bramnik
似乎与泛型有关。该类是参数化的,即SomeClass<T>,其中包含一个私有实例变量T[]。如果删除该变量,则可以正常工作。否则,会抛出许多类型的异常,具体取决于变化情况。 - PNS
1
这听起来你应该使用 SomeClass<T extends Serializable> - Dahaka
1
即使这样也不起作用。请参阅上面的问题的详细版本。 - PNS
2个回答

11

0

请确保在序列化和反序列化时使用相同的类版本。如果您使用一个类版本进行序列化,然后使用不同的类版本(例如添加或删除字段后)则可能会发生此错误。这并不意味着它只能在那种情况下发生。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接