O assunto já havia sido discutido em dois tópicos (http://guj.com.br/posts/list/136307.java e http://guj.com.br/posts/list/143727.java) e também há uma issue no github para o caso.
Relato aqui de novo minhas considerações sobre o uso de um elegante exception handler no vraptor. Resolvi ressuscitar a discução porque recebi algumas MP me pedindo o código do exception handler, e achei que é bem melhor termos uma solução assim build-in no próprio vraptor do que ficar fazendo isso em cada projeto separadamente, já que o vraptor ainda não suporta tal recurso.
Diz a regra que todas as especificações devem ser tratadas na sua camada mais externa com os nossos amigos try and catch. Porém muitas vezes tratar isso a cada controller e fazer simplesmente um try and catch para simplesmente redirecionar para uma view e exibir uma mensagem já tratada torna-se bem repetitivo.
Um exemplo: minhas aplicações usam EJB remoto, e o vraptor atua apenas como controlador. Se estou em um método de editar usuário, e quando vou salvar um usuário dá alguma regra de negócio, por exemplo usuário já existente, eu normalmente volto para a tela de edição e exibo a mensagem de erro. Manualmente eu faria isso aqui:
[code]public void edit(Long id) {
[…]
}
public void store(User user) {
try {
// podem ocorrer erros de negócio aqui
userService.storeNewUser(user);
// se der certo redireciona para a listagem
result.redirectTo(getClass()).listAll();
} catch(MyBusinessException e) {
// deu erro, adiciono manualmente nas mensagens
validator.add(new ValidationMessages(e.getMessage(), “error”);
// redireciono para a tela de edição para o usuario corrigir o problema
result.forwardTo(getClass()).edit(user.getId());
}
// posso tratar outras exceptions aqui
}[/code]
Mas como meus projetos normalmente são muito grandes (um deles possui ~350 controllers) ficaria muito cansativo fazer isso método por método. Nesses outros tópicos tirei minhas dúvidas com a galera do Vraptor sobre como fazer um bom exception-handler, estilo ao que o nosso velho amigo Struts 1 fazia elegantemente. Usando minha proposta o código acima fica reduzido em algo como isso:
[code]public void edit(Long id) {
[…]
}
public void store(User user) {
// se ocorrer um erro não tratado vai para a tela de edição
result.onErrorUse(getClass()).edit(user.getId());
// podem ocorrer erros de negócio aqui
userService.storeNewUser(user);
// se der certo redireciona para a listagem
result.redirectTo(getClass()).listAll();
}[/code]
O código não apenas ficou bem menor como mais legível do que um monte de try and catch aninhado. Obvio que nada me impede de tratar as exceptions manualmente, porém o exception handler irá atuar sempre o programador não tratar tal exception. Fiz uns testes e até mesmo erro de JSP é capturado aqui. Há mais relatos nesse meu post: http://guj.com.br/posts/list/45/136307.java#804730
Nas discuções anteriores houve preocupações que isso pode parecer um try/catch mascarando todos os erros. Porém esse erro é repassado para a tela, exibindo a mensagem e não a mascarando. http://guj.com.br/posts/list/45/136307.java#804743
Inclusive a sugestão do Paulo e do Sérgio é de usar o web.xml e o atributo error-page, o que na minha opinião não é bom porque assim só posso exibir uma tela bonita, ao invés de poder voltar para a tela para que o erro possa ser tratado. (http://guj.com.br/posts/list/45/136307.java#805689)
(edição) Os códigos seguem abaixo já que não consigo enviar meus gists. A minha sugestão é adicionar o método onErrorUse na interface Result e suas implementações, e alterar o ExecuteMethodInterceptor para trabalhar com essa classe, conforme o que escrevi abaixo.