We've encountered a problem with Wicket 6 (namely version 6.22.0). It looks like it is what was fixed here: https://issues.apache.org/jira/browse/WICKET-5068
In a few words: after the page expires, Wicket tries to reconstruct it by calling a constructor with page class and PageParameters
as arguments, but PageParameters
is (erroneously) empty even though some parameters were sent with the request.
After Wicket session timeout - pageParameters are null seems to be relating to the same issue.
WICKET-5068 has a fix for Wicket 7, but we are having Wicket 6 and we need a fix for it.
Following is a lengthy explanation of our findings and some questions.
Here is what happens:
- User opens a page (it is stateful) and leaves it open in a browser tab.
- User opens other pages
- The original page from step 1 is evicted from Page Store (i.e. gets expired) although the session is still up.
User returns to the initial browser tab and clicks on a link. Here is the code of the link:
AjaxLink<Void> link = new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { showWindow(dataModel, window, target); } }; add(link);
While
BookmarkableMapper
buildsIRequestHandler
from the request, the following method is called (AbstractBookmarkableMapper:294):protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) { if (pageInfo.getPageId() != null) { // WICKET-4594 - ignore the parsed parameters for stateful pages return null; } return pageParameters; }
So the
ListenerInterfaceRequestHandler
that is built from the request hasnull
forPageParameters
.Wicket starts processing the click. It tries to restore the page to which the clicked link belongs, this is done in the following method (PageProvider, starts at line 252):
private void resolvePageInstance(Integer pageId, Class<? extends IRequestablePage> pageClass, PageParameters pageParameters, Integer renderCount) { IRequestablePage page = null; boolean freshCreated = false; if (pageId != null) { page = getStoredPage(pageId); } if (page == null) { if (pageClass != null) { page = getPageSource().newPageInstance(pageClass, pageParameters); freshCreated = true; } } if (page != null && !freshCreated) { if (renderCount != null && page.getRenderCount() != renderCount) { throw new StalePageException(page); } } pageInstanceIsFresh = freshCreated; pageInstance = page; }
As the page is evicted from page store, the following statement's condition holds:
if (page == null)
So it tries to create a page instance from class and page parameters:
page = getPageSource().newPageInstance(pageClass, pageParameters);
But
pageParameters
isnull
here (because ofgetPageParametersForListener()
from item 5). So the page constructor gets emptyPageParameters
and fails as it expects some id.
Here is the code to extract an id from PageParameters
in the page constructor:
pageParameters.get("id").toLong()
Here is the exception that is produced (only showing the top lines as the rest is not relevant):
org.apache.wicket.util.string.StringValueConversionException: Unable to convert 'null' to a long value
at org.apache.wicket.util.string.StringValue.toLong(StringValue.java:664)
So in our case getPageParametersForListener()
method breaks a possibility to restore processing of an expired page.
Trying to fix this, we've replaced the BookmarkableMapper
with our custom implementation:
public class BookmarkableMapperThatSavesPageParametersForListener extends BookmarkableMapper {
@Override
protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) {
return pageParameters;
}
}
which we mount in WebApplication#init()
method:
mount(new BookmarkableMapperThatSavesPageParametersForListener());
It seems to fix the problem we were faced with: the link click does not fire the handler (onClick()
method), but at least the page does not explode and just refreshes itself.
The questions are:
- Does this happen because we do something wrong or it is a bug in Wicket?
- Is the fix we applied eligible? I guess the change introduced by https://issues.apache.org/jira/browse/WICKET-4594 was not made just for fun
- Would our fix break anything knowing that we only have stateful pages?