编年史:对象在反序列化期间未初始化

Chronicle: object not initialized during deserialization

我目前有 class,其中一些字段在声明中已初始化,如下所示:

public class SomeClass implements Externalizable {

    private long id; 

    private final List<Hit> hits = new ArrayList<>();

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeLong(id);
        out.writeInt(hits.size());
        for (int i = 0; i < hits.size(); i++) {
            out.writeObject(hits.get(i));
        }
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        id = in.readLong();
        int size = in.readInt();
        for (int i = 0; i < size; i++) {
             hits.add((Hit) in.readObject()); //<--Nullpointer here, hits == null
        }
    }
}

而这个 class 用于基于文件的 chronicle-map 配置如下:

ChronicleMap<Long, SomeClass> storage = ChronicleMapBuilder
            .of(Long.class, SomeClass.class)
            .averageValueSize(avgEntrySize)
            .entries(entries)
            .createPersistedTo(new File(path));

问题是当我重新启动我的应用程序时,当 chronicle 试图读取保存的地图时我得到 NullpointerException,因为 hits 字段没有初始化,这意味着它是 null

我做了一些调查,发现在调用 readExternal 之前,chronical 使用 UNSAFE.allocateInstance(in ExternalizableMarshaller):

创建了这个 class 的对象
protected E getInstance() throws Exception {
    return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
}

所以基本上这就是它没有初始化的原因。我想了解为什么它使用这种方法而不是 MethodHandle 或反射?

也许还有另一种方法可以在不修改 SomeClass 的情况下解决这个问题,比如一些编年史配置 属性 也许?

这似乎是不再受支持的版本 2.x 的问题。

在版本 3.x 中,它应该调用默认构造函数(如果存在的话)。如果没有默认构造函数,它将使用 Unsafe。我添加了一个测试用例,它在 3.x

中显示了它的工作原理

https://github.com/OpenHFT/Chronicle-Map/blob/master/src/test/java/net/openhft/chronicle/map/externalizable/ExternalizableTest.java

对于版本2.x建议您需要查看列表是否为null,根据需要设置