2010-07-21 2 views
3

Я написал свой класс Container<T>, который создает резервные копии своих T элементов в нескольких коллекциях - первичный - List<T>, другие - разные карты с данными, полученными из элементов, в основном для оптимизированного поиска.Deserialized object имеет значение null во всех полях

класса выглядит следующим образом:

class Container<T> implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private final List<T> items = Lists.newArrayList(); 
    private final Map<...> map1 = Maps.newHashMap(); 
    private final Map<...> map2 = Maps.newHashMap(); 
} 

Стандартный сериализации работает как шарм, но карты не нужно сериализовать. Я попытался установить карты в качестве transient и использовать readObject() таким образом:

class Container<T> implements Serializable { 
    private static final long serialVersionUID = 1L; 

    private final List<T> items = Lists.newArrayList(); 
    private transient Map<...> map1; 
    private transient Map<...> map2; 

    public Container() { 
     initContainer(); 
    } 

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 
     in.defaultReadObject(); 
     initContainer(); 
    } 

    private void initContainer() { 
     map1 = Maps.newHashMap(); 
     map2 = Maps.newHashMap(); 
     // prepare data in maps 
     for (T item: items) { 
      map1.put(...); 
      map2.put(...); 
     } 
    } 
} 

Простой тест с ObjectOutputStream.writeObject() и ObjectInputStream.readObject() снова работает. Но когда я интегрирую Container в реальное приложение, где этот класс сериализуется и десериализуется как часть других сложных классов (фактически на странице Wicket), происходят странные вещи.

Я сделал некоторые отладки и вот мои выводы:

  • сериализация Container с (п) элементами сделали OK
  • десериализация Container сделала OK
  • десериализации каждого T элемента называется только (n-1) раз (путем подсчета звонков на его метод readObject())
  • в containerInit() имеет List<T> правильный (n) количество элементов, но один из них (Что один, для которого не называется десериализации) находится в очень странном состоянии - все поля имеют null значение - и мой код здесь бросает NPE

Вопросы:

  • Какое состояние имеет этот странный объект после десериализации (он существует, но без readObject() вызов и с нулевым значением во всех полях)?
  • Возможно, десериализация этого странного объекта не завершена, но я прочитал, что чтение объектов из ObjectInputStream блокируется, поэтому все объекты в моем списке должны быть в правильном состоянии. Или я что-то забыл?
  • Есть ли какая-либо техника/инструмент/практика для ловли вещей вроде этого?

спасибо.

+0

Пара вопросов: неупорядочен ли десериализованный объект один и тот же? Если да, то как его состояние отличается от других? Кроме того, всякий раз, когда десериализуются объекты, неплохо предположить, что они из враждебного источника и соответственно проверяют их состояние для таких вещей, как нули или что-то еще, что скомпрометирует ваше приложение. –

+0

Этот объект не одинаковый в каждом случае, прежде чем сериализация ссылается на пару других объектов в приложении - это полностью здоровый объект, прежде чем сериализация вызывает метод 'writeObject()'. У меня есть еще один важный вывод: когда я не перехожу через 'items' в' Container.readObject() '(или' initContainer() 'на самом деле), все работает! Похоже, я не могу коснуться десериализованных данных right-now в 'readObject()', он должен быть отложен после завершения сериализации. Возможно, это зависит от существующих ссылок на объект до начала сериализации ... очень странно ... – mschayna

ответ

0

Как я писал в комментарии, проблема заключалась в касании элементов в сериализованной коллекции в течение Container.readObject(). Некоторые из этих объектов имели в этот момент нулевые поля. Когда я отложил их касательную внешнюю десериализацию Container, эти объекты имели правильные значения полей.

Моя гипотеза:

Позволяет иметь объект родительский с коллекцией поля других объектов детей. Оба родителя и дети являются сериализуемыми, а также коллекция.Во время настраиваемой родительской десериализации в readObject() метод не является полностью доступным для детей, они существуют, но его десериализация не завершена. Вы должны обращаться к детям только после обработки десериализации родителя.

Эта гипотеза работает для меня, но я до сих пор не знаю почему.

Смежные вопросы