Хроника: объект не инициализирован во время десериализации - PullRequest
0 голосов
/ 05 июня 2018

В настоящее время у меня есть класс, некоторые поля которого инициализированы в объявлении, например:

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, когда хроника пытается прочитать сохраненную карту, потому что поле hits не было инициализировано, то есть null.

Я провел некоторое исследование иобнаружил, что перед вызовом readExternal хронический создает объект этого класса, используя UNSAFE.allocateInstanceExternalizableMarshaller):

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

Так что в основном это причина, по которой он не инициализирован.Что я пытаюсь понять, почему он использует такой подход вместо MethodHandle или рефлексии?

И, может быть, есть другой способ исправить это без изменения SomeClass, как, например, какое-то свойство конфигурации хроники?

1 Ответ

0 голосов
/ 05 июня 2018

Это, похоже, проблема с версией 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 и установить егопо мере необходимости.

...