简体   繁体   English

Wicket序列化/反序列化问题

[英]Wicket serialization/deserialization issue

Assume following component tree: 假设以下组件树:

  • A 一种
    • B
    • C C

A has a private field (called filter) and the reference to the filter is passed on to B and C. In class B a property of the filter is modified through an AjaxLink (so no page refresh). A有一个私有字段(称为过滤器),对过滤器的引用传递给B和C.在类B中,过滤器的属性通过AjaxLink进行修改(因此没有页面刷新)。 I see (through) logging that after each ajax call wicket will serialize A, B and C. 我看到(通过)记录在每次ajax调用wicket之后将序列化A,B和C.

Now, everything works fine, clicking in the AjaxLinks in B will nicely update the filter and will refresh C and show the correct information in C (based on the filter). 现在,一切正常,单击B中的AjaxLinks将很好地更新过滤器并刷新C并在C中显示正确的信息(基于过滤器)。

However, assume if click an AjaxLink in B which will update a property of the filter to (for instance) value 2. Afterwards I press F5, it still works and the page (and all components in it) is deserialized (and again serialized afterwards). 但是,假设在B中单击一个AjaxLink,它会将过滤器的属性更新为(例如)值2.然后我按F5,它仍然有效并且页面(及其中的所有组件)被反序列化(之后再次序列化) )。 I then click on an AjaxLink the changes the value of the mentioned property to 3; 然后我点击一个AjaxLink,将提到的属性的值更改为3; this still works fine. 这仍然很好。 If, however, I then do a page refresh (F5) the value of that property suddenly becomes 2 again. 但是,如果我然后进行页面刷新(F5),则该属性的值突然再次变为2。

It seems that on the page refresh (when wicket will load the page from disk) wicket is deserializing an older version of the filter. 似乎在页面刷新(当wicket将从磁盘加载页面时)wicket正在反序列化旧版本的过滤器。

Schematically: 示意图:

  1. Page initial load: 页面初始加载:
    => filter.value = 3 -> serialized => filter.value = 3 - >序列化
  2. AjaxLink: AjaxLink:
    => filter.value = 2 -> serialized => filter.value = 2 - >序列化
  3. Page refresh: 页面刷新:
    => filter.value = 2 -> deserialized/serialized => filter.value = 2 - > 反序列化/序列化
  4. AjaxLink: AjaxLink:
    => filter.value = 3 -> serialized => filter.value = 3 - >序列化
  5. Page refresh: 页面刷新:
    => filter.value = 2 -> deserialized/serialized => filter.value = 2 - > 反序列化/序列化

It seems that on action 5 the serialized version after action 4 is ignored and the serialized version after action 3 the loaded. 似乎在操作5中,操作4之后的序列化版本被忽略,并且在操作3之后的序列化版本被加载。

Hoping for a cause, explanation and if possible also the solution :-) 希望有一个原因,解释,如果可能还有解决方案:-)

CODE

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);
         ...
    }    
}

Code has been simplified and I retained only the (I assume) pertinent stuff. 代码已经简化,我只保留(我假设)相关的东西。

UPDATE UPDATE

If I add following in my page class then it works: 如果我在我的页面类中添加以下内容则可以:

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

Not sure however about the implications of this and why this makes it work. 然而,不确定这个的含义以及为什么这会使它起作用。 Isn't the page (de)serialized anymore? 页面(de)不再序列化了吗?

UPDATE UPDATE

I added following to my Page class: 我在页面类中添加了以下内容:

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. When the Page is loaded first it prints (actually it prints this 5 times, not sure if it's normal): Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = ALL 当页面被加载时,它首先打印(实际上它打印了5次,不确定它是否正常):写[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]: type = ALL

  2. When I click on AjaxLink 'ALL' (that will update the filter) it still prints: Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = ALL 当我点击AjaxLink'ALL'(将更新过滤器)时,它仍会打印:写入[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = ALL

  3. When I click on AjaxLink 'DISCUSSIONS' (that will update the filter) it still prints: Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS 当我点击AjaxLink'DISCUSSIONS'(将更新过滤器)时,它仍会打印:写入[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = DISCUSSIONS

  4. When I refresh the page (F5) the pageid is updated: Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 2]: type = DISCUSSIONS 当我刷新页面(F5)时,更新了pageid:写入[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 1,render count = 2]:type = DISCUSSIONS

  5. When I click on AjaxLink 'ALL' (that will update the filter) it prints: Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 1, render count = 1]: type = ALL 当我点击AjaxLink'ALL'(将更新过滤器)时,它会打印:写入[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 1,render count = 1]:type = ALL

  6. So far so good but when I refresh the page now (F5) this is printed out: Reading [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 0, render count = 1]: type = DISCUSSIONS Writing [Page class = com.bnpp.ecom.homepage.web.Homepage, id = 2, render count = 2]: type = DISCUSSIONS 到目前为止这么好,但是当我现在刷新页面时(F5)打印出来:读取[Page class = com.bnpp.ecom.homepage.web.Homepage,id = 0,render count = 1]:type = DISCUSSIONS Writing [Page class = com.bnpp.ecom.homepage.web.Homepage,id = 2,render count = 2]:type = DISCUSSIONS

The url never changes, it stays http://.../?0 网址永远不会改变,它保持http://.../?0

So it deserializes the page with id 0 although the last known page id was 1 and all changes that were done for version 1 are ignored (in this case switching the type from DISCUSSIONS to ALL). 因此,它将id为0的页面反序列化,尽管最后一个已知的页面id为1,并且忽略了对版本1所做的所有更改(在这种情况下,将类型从DISCUSSIONS切换为ALL)。

Created a issue in the wicket jira for this: https://issues.apache.org/jira/browse/WICKET-4360 在wicket jira中为此创建了一个问题: https//issues.apache.org/jira/browse/WICKET-4360

Watch the browser's url When you refresh the page. 观看浏览器的URL当您刷新页面时。 It probably includes the Wicket page version, so when you refresh a second time, a specific version of the page is deserialized. 它可能包含Wicket页面版本,因此当您第二次刷新时,将反序列化特定版本的页面。

Since you keep the filter in your page, it is serialized/deserialized along with its containing components. 由于您将过滤器保留在页面中,因此会对其包含的组件进行序列化/反序列化。

A solution would be to put the filter into the session. 解决方案是将过滤器放入会话中。

As mentioned in the jira issue: https://issues.apache.org/jira/browse/WICKET-4360 you need to setreuseitems on listviews to true or an ajax call will dirty your page when the listview is repopulated: 正如jira问题中所述: https ://issues.apache.org/jira/browse/WICKET-4360您需要将listview上的setreuseitems设置为true,否则当重新填充listview时,ajax调用会弄脏您的页面:

On F5 Wicket reads (once) the current page. 在F5 Wicket读取(一次)当前页面。 But then it writes a the page with a new page id because of the usage of ListView (PropertyListView in DataPanel). 但是由于使用了ListView(DataPanel中的PropertyListView),它会用新的页面ID写一个页面。 By adding "commentsListView.setReuseItems(true);" 通过添加“commentsListView.setReuseItems(true);” all is fine. 一切都很好。 See WICKET-4286 for a discussion about the ListView problem. 有关ListView问题的讨论,请参阅WICKET-4286

In your log statements, it seems like its only reading on the fifth request. 在您的日志语句中,它似乎是第五个请求的唯一读数。 That's probably why it works on the first page refresh. 这可能就是为什么它适用于第一页刷新。

Wicket serializes the page each time, but it keeps the last version of the page in memory and only de-serializes it if a previous version is requested. Wicket每次都会对页面进行序列化,但它会将页面的最后一个版本保留在内存中,并且只有在请求以前版本时才对其进行反序列化。

If you check the hashCode of the Filters in the A, B, and C Components, you'll probably see they are different objects after deserialization. 如果检查A,B和C组件中的过滤器的hashCode,您可能会在反序列化后看到它们是不同的对象。 Instead of passing around a Filter, pass around a model which returns the Filter from Component A. If component A is a Page, it's really easy because every Component can invoke getPage().getDefaultModel() or getDefaultModelObject(). 而不是传递一个Filter,而是传递一个模型,该模型从组件A返回Filter。如果组件A是一个Page,那么它非常简单,因为每个Component都可以调用getPage()。getDefaultModel()或getDefaultModelObject()。 If Component A is a Panel, try navigating to it with getPage().get("A").getDefaultModel(). 如果组件A是Panel,请尝试使用getPage()。get(“A”)。getDefaultModel()导航到它。

I think if the app is using the same Filter object, serialization wont matter. 我认为如果应用程序使用相同的Filter对象,序列化无关紧要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM