Проблема сериализации / десериализации калитки - PullRequest
0 голосов
/ 24 января 2012

Предположим, следующее дерево компонентов:

  • A
    • B
    • C

A имеет закрытое поле (называемое фильтром), и ссылка на фильтр передается B и C. В классе B свойство фильтра изменяется через AjaxLink (поэтому обновление страницы не требуется). Я вижу (через) ведение журнала, что после каждого вызова ajax калитка будет сериализовать A, B и C.

Теперь все работает нормально, щелкнув AjaxLinks в B, вы обновите фильтр, обновите C и покажете правильную информацию в C (в зависимости от фильтра).

Однако, предположим, если щелкнуть AjaxLink в B, который обновит свойство фильтра до (например) значения 2. После этого я нажимаю F5, он все еще работает, и страница (и все компоненты в ней) десериализуется (и снова сериализовано впоследствии). Затем я нажимаю на AjaxLink, чтобы изменить значение указанного свойства на 3; это все еще работает отлично. Однако если я затем обновлю страницу (F5), значение этого свойства снова станет равным 2.

Похоже, что при обновлении страницы (когда wicket загрузит страницу с диска) wicket десериализует старую версию фильтра.

Схематично:

  1. Начальная загрузка страницы:
    => filter.value = 3 -> сериализовано
  2. AjaxLink:
    => filter.value = 2 -> сериализовано
  3. Обновление страницы:
    => filter.value = 2 -> десериализованный / сериализованный
  4. AjaxLink:
    => filter.value = 3 -> сериализовано
  5. Обновление страницы:
    => filter.value = 2 -> десериализованный / сериализованный

Кажется, что на действии 5 сериализованная версия после действия 4 игнорируется, а сериализованная версия после действия 3 загружается.

Надеясь на причину, объяснение и, если возможно, также решение: -)

КОД

public class A extends Panel { //creates the filter and passes the reference on 
        Filter filter = new Filter(TypeEnum.ALL);

    public A(final String id) {
        super(id);

    add(new B("filterPanel", filter));
    add(new C("datatable", filter));
}



    public class B extends Panel { //updates the filter

        Filter filter;;
        public B(final String id, Filter filter) {
            super(id);
            this.filter = filter;
            add(new IndicatingAjaxLink<Void>("other") {

            @Override
            public void onClick(AjaxRequestTarget target) {
                filter.setType(TypeEnum.OTHER);
                            ...
            }
        };
        }

    }

public class C extends Panel { //uses the filter

    Filter filter;;
    public C(final String id, Filter filter) {
            super(id);
            this.filter = filter;
    }

    public void populateRepeatingView() {
         final List<? extends WallEntry> result = service.find(filter);
         ...
    }    
}

Код был упрощен, и я сохранил только (я полагаю) соответствующие вещи.

UPDATE

Если я добавлю следующее в свой класс страниц, то это сработает:

@Override
public boolean isVersioned() {
    return false;
}

Не уверен, однако, о последствиях этого и почему это заставляет его работать. Страница больше не сериализуется?

UPDATE

Я добавил следующее в свой класс Page:

private void writeObject(ObjectOutputStream oos) throws IOException { 
oos.defaultWriteObject(); 
System.err.println("Writing " + this + something to print out the type of the filter); 
} 

private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { 
ois.defaultReadObject(); 
System.err.println("Reading " + this + something to print out the type of the filter); 
} 
  1. Когда страница загружается первой, она печатает (на самом деле печатает это 5 раз, не уверен, что это нормально): Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = ALL

  2. Когда я нажимаю на AjaxLink 'ALL' (это обновит фильтр), он все равно печатает: Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = ALL

  3. Когда я нажимаю на AjaxLink 'DISCUSSIONS' (которая обновит фильтр), он все равно печатает: Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS

  4. Когда я обновляю страницу (F5), pageid обновляется: Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 2]: type = DISCUSSIONS

  5. Когда я нажимаю на AjaxLink 'ALL' (это обновит фильтр), он печатает: Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 1]: type = ALL

  6. Пока все хорошо, но когда я обновляю страницу сейчас (F5), это распечатывается: Чтение [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS Запись [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 2, render count = 2]: type = DISCUSSIONS

URL никогда не меняется, он остается http: //.../? 0

Таким образом, он десериализует страницу с идентификатором 0, хотя последний известный идентификатор страницы был 1, и все изменения, которые были сделаны для версии 1, игнорируются (в этом случае переключение типа с DISCUSSIONS на ALL).

Создана проблема в калитке jira для этого: https://issues.apache.org/jira/browse/WICKET-4360

Ответы [ 3 ]

1 голос
/ 27 января 2012

Как уже упоминалось в выпуске jira: https://issues.apache.org/jira/browse/WICKET-4360 вам нужно установить для элементов списка значения просмотра в true или вызов ajax испортит вашу страницу при повторном заполнении списка:

в F5 Wicketчитает (один раз) текущую страницу.Но затем он записывает страницу с новым идентификатором страницы из-за использования ListView (PropertyListView в DataPanel).Добавляя "commentsListView.setReuseItems (true);"Все хорошо.См. WICKET-4286 для обсуждения проблемы ListView.

1 голос
/ 24 января 2012

Просмотр URL браузера при обновлении страницы.Вероятно, она включает версию страницы Wicket, поэтому при повторном обновлении конкретная версия страницы десериализуется.

Поскольку фильтр на странице сохраняется, он сериализуется / десериализуется вместе с содержащими его компонентами..

Решением будет использование фильтра в сеансе.

0 голосов
/ 27 января 2012

В ваших отчетах журнала кажется, что это только чтение по пятому запросу. Вероятно, поэтому он работает при обновлении первой страницы.

Wicket сериализует страницу каждый раз, но сохраняет в памяти последнюю версию страницы и десериализует ее только в случае запроса предыдущей версии.

Если вы проверите хэш-код фильтров в компонентах A, B и C, вы, вероятно, увидите, что это разные объекты после десериализации. Вместо того, чтобы обойти фильтр, передайте модель, которая возвращает фильтр из компонента А. Если компонент А является страницей, это действительно просто, потому что каждый компонент может вызывать getPage (). GetDefaultModel () или getDefaultModelObject (). Если компонент A является панелью, попробуйте перейти к нему с помощью getPage (). Get ("A"). GetDefaultModel ().

Я думаю, что если приложение использует тот же объект Filter, сериализация не имеет значения.

...