Assume following component tree:
- A
- B
- 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). I see (through) logging that after each ajax call wicket will serialize A, B and 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).
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). I then click on an AjaxLink the changes the value of the mentioned property to 3; this still works fine. If, however, I then do a page refresh (F5) the value of that property suddenly becomes 2 again.
It seems that on the page refresh (when wicket will load the page from disk) wicket is deserializing an older version of the filter.
Schematically:
- Page initial load:
=> filter.value = 3 -> serialized - AjaxLink:
=> filter.value = 2 -> serialized - Page refresh:
=> filter.value = 2 -> deserialized/serialized - AjaxLink:
=> filter.value = 3 -> serialized - Page refresh:
=> filter.value = 2 -> deserialized/serialized
It seems that on action 5 the serialized version after action 4 is ignored and the serialized version after action 3 the loaded.
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
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?
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);
}
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
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
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
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
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
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
The url never changes, it stays 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).
Created a issue in the wicket jira for this: https://issues.apache.org/jira/browse/WICKET-4360
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: