Página da web sem estado no Wicket

Outro dia, fui detido por um recurso bastante irritante do Wicket, a maneira como ele determina se uma página deve ou não ser sem estado.

Se uma página for stateful, o Wicket redireciona montagens de página para montagens com versão (na forma de <mount>? <page-id>). Ele faz isso para ser capaz de renderizar novamente quaisquer atualizações após a renderização da página inicial, em uma atualização do navegador ou quando um usuário pressiona o botão Voltar.

Se você usar muitas atualizações de ajax em uma página, esse comportamento é bastante útil. Se você não quiser e quiser mostrar modificações em uma atualização do navegador (porque você tem apenas um cliente que acredita que muitas pessoas não têm javascript), você precisa ter uma página sem estado.

A parte irritante é que é muito difícil controlar se sua página é ou não sem estado ou com estado, sem falar que esse comportamento dificilmente é documentado. Passei por listas de discussão e código-fonte por cerca de 2 horas para descobrir exatamente o que estava errado.

Já vi soluções que alteram os pontos de montagem para que o redirecionamento não aconteça. Embora isso possa funcionar em alguns casos, deixa a página um tanto danificada e pode causar efeitos colaterais inesperados (você sabe, aqueles que o Wicket está cheio).

Para determinar se sua página é sem estado, o Wicket visita todos os componentes da página e pergunta se eles são sem estado. Em sua página, você pode apenas sugerir ao Wicket que deseja que a página não tenha estado (Page.setStatelessHint), mas isso dificilmente influencia em nada.

Se sua página contém qualquer componente que não seja sem estado, você não tem escolha a não ser alterar / excluir o componente ou aceitar o redirecionamento. Mas como você encontraria esse componente? Nem sempre é óbvio quais componentes têm estado. Por exemplo, seria razoável esperar que um link não tivesse estado. No entanto, se não for um link que pode ser marcado, o componente do link terá estado (há boas razões no Wicket para isso).

Para localizar o componente com estado na página que eu precisava ser sem estado, escrevi um teste usando um visitante para localizar o componente com estado. Escrevi um matcher hamcrest para afirmar que uma página não tem estado. Se a página tiver estado, ele diagnostica imprimindo a id do postigo do (primeiro) componente com estado.

Eu coloquei o StatelessPageMatcher em um Gist. Um teste que o usa pode ter a seguinte aparência.

@Test public void page_is_stateless() throws Exception {
WebPage page = wicketTester.startPage(MyPage.class);
assertThat
(page, is(stateless()));
}

Espero que isso ajude alguém!