Wicket序列化/反序列化问题

时间:2012-01-24 11:09:34

标签: java serialization wicket wicket-1.5

假设以下组件树:

    • C

A有一个私有字段(称为过滤器),对过滤器的引用传递给B和C. 在B类中,通过AjaxLink修改过滤器的属性(因此不进行页面刷新)。 我看到(通过)记录在每次ajax调用wicket之后将序列化A,B和C.

现在,一切正常,单击B中的AjaxLinks将很好地更新过滤器并刷新C并在C中显示正确的信息(基于过滤器)。

但是,假设在B中单击一个AjaxLink,它会将过滤器的属性更新为(例如)值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 - >的反序列化/串行化
  6. 似乎在操作5中,操作4之后的序列化版本被忽略,并且在操作3之后的序列化版本被加载。

    希望找到原因,解释以及可能的解决方案: - )

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

    代码已经简化,我只保留(我假设的)相关内容。

    更新

    如果我在我的页面类中添加以下内容,那么它可以工作:

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

    不确定这个的含义以及为什么这会使它起作用。页面(de)不再序列化了吗?

    更新

    我在页面课程中添加了以下内容:

    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

    7. 网址永远不会改变,它会保持http://.../?0

      因此,它将ID为0的页面反序列化,尽管最后一个已知的页面ID为1,并且忽略了对版本1所做的所有更改(在这种情况下,将类型从DISCUSSIONS切换为ALL)。

      在wicket jira中为此创建了一个问题:https://issues.apache.org/jira/browse/WICKET-4360

3 个答案:

答案 0 :(得分:1)

观看浏览器的网址刷新页面时。它可能包含Wicket页面版本,因此当您第二次刷新时,将对该页面的特定版本进行反序列化。

由于您将过滤器保留在页面中,因此会对其包含的组件进行序列化/反序列化。

解决方案是将过滤器放入会话中。

答案 1 :(得分:1)

正如jira问题所述:https://issues.apache.org/jira/browse/WICKET-4360您需要将listview上的setreuseitems设置为true,否则当重新填充listview时,ajax调用会弄脏您的页面:

  

在F5上,Wicket读取(一次)当前页面。但后来它写了一个   由于ListView的使用,页面具有新的页面ID   (DataPanel中的PropertyListView)。通过增加   “commentsListView.setReuseItems(真)”;一切都很好。见WICKET-4286   有关ListView问题的讨论。

答案 2 :(得分:0)

在您的日志语句中,它似乎是第五次请求的唯一读数。这可能就是为什么它适用于第一页刷新。

Wicket每次都会序列化页面,但它会将页面的最后一个版本保留在内存中,并且只有在请求以前的版本时才会对其进行反序列化。

如果检查A,B和C组件中的过滤器的hashCode,您可能会在反序列化后看到它们是不同的对象。而不是传递一个Filter,而是传递一个模型,该模型从组件A返回Filter。如果组件A是一个Page,那么它非常简单,因为每个Component都可以调用getPage()。getDefaultModel()或getDefaultModelObject()。如果组件A是Panel,请尝试使用getPage()导航到它.get(“A”)。getDefaultModel()。

我认为如果应用程序使用相同的Filter对象,则序列化无关紧要。