代码之家  ›  专栏  ›  技术社区  ›  Ruslan Akhundov

历史记录:反序列化期间未初始化对象

  •  1
  • Ruslan Akhundov  · 技术社区  · 7 年前

    我现在有一个类,它在声明中初始化了一些字段,如下所示:

    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
            }
        }
    }
    

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

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

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

    我做了一些调查,发现在打电话之前 readExternal Chronical使用 UNSAFE.allocateInstance ExternalizableMarshaller ):

    protected E getInstance() throws Exception {
        return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
    }
    

    所以基本上这就是它没有初始化的原因。我试图理解的是为什么它使用这种方法而不是 MethodHandle 还是反思?

    也许有另一种方法可以解决这个问题而不需要修改 SomeClass ,比如一些历史配置属性?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Peter Lawrey    7 年前

    这似乎是不再受支持的版本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 并根据需要进行设置。

    推荐文章