Stateless web page in Wicket
The other day I was held back by a rather annoying feature of Wicket, the way it determines whether or not a page should be stateless.
If a page is stateful Wicket redirects page mounts to versioned mounts (in the form of <mount>?<page-id>). It does so to be able to re-render any updates after the initial page rendering, on a browser refresh or when a user hits the back button.
If you use a lot of ajax updates on a page this behavior is actually quite useful. If you don't and want to show modifications on a browser refresh (because you just have such a customer who believes that many people have no javascript) you need to have a stateless page.
The annoying part is that it's pretty hard to control whether or not your page is stateless or stateful, let alone that this behavior is hardly documented. I went through mailing lists and source code for about 2 hours to figure out exactly what was wrong.
I've seen work-arounds that hack the mount points so that the redirect does not happen. While this might work in some cases it leaves the page rather crippled and might cause unexpected side-effects (you know, those that Wicket is just full of).
To determine whether your page is stateless Wicket visits all components on the page and asks them if they are stateless. On your page you can only hint Wicket that you want the page to be stateless (Page.setStatelessHint), but this hardly influences anything.
If your page contains any component that is not stateless, you have no choice but to change/delete the component or accept the redirect. But how would you find this component? It is not always obvious what components are stateful. For example, you would reasonably expect a link to be stateless. However, if it's not a bookmarkable link the link component is actually stateful (there are good reasons within Wicket for this).
To find the stateful component on the page I needed to be stateless, I wrote a test using a visitor to find the stateful component. I wrote a hamcrest matcher to assert that a page is stateless. If the page is stateful, it diagnoses by printing the wicket id of the (first) stateful component.
I put the StatelessPageMatcher in a Gist. A test that uses it could look like the following.
@Test public void page_is_stateless() throws Exception {
WebPage page = wicketTester.startPage(MyPage.class);
assertThat(page, is(stateless()));
}
Hope this helps someone!
Written by Bart Bakker
Related protips
2 Responses
You can also install a stateless checker in your WebApplication::init() method: "getComponentPostOnBeforeRenderListeners().add(new StatelessChecker())", and then annotate each page you want to check with @StatelessComponent.
You can also install a stateless checker in your WebApplication::init() method: "getComponentPostOnBeforeRenderListeners().add(new StatelessChecker())", and then annotate each page you want to check with @StatelessComponent.