JSF: Validação na fase correta

For the english version, click here.

Para o post dessa semana resolvei falar em algo relacionado ao artigo passado, vou falar um pouco sobre o ciclo de vida do JSF. Acredito que uma maneira fácil de vislumbrar porque é importante entender o ciclo de vida de aplicações JSF, é por meio de algo bem simples e que fazemos toda hora: validar input do usuário.

De maneira geral, o entendimento do chamado JSF Life Cycle é o que faz a diferença entre o profissional que copia e cola o código e tem muita dificuldade quando se depara com situações incomuns (incomum nessa área pode-se até considerar comum), e o profissional que tem capacidade de sair do outro lado sem comprometer a qualidade do que está fazendo.
Quando vou entrevistar alguém, principalmente desenvolvedores seniores/plenos que dizem ter anos de experiência com JSF, não saber o ciclo de vida é em 99% dos casos sinal de eliminação 🙂

Visão Geral

Quem já estudou JSF pelo menos uma vez na vida já deve ter visto essa figurinha aqui embaixo:

ciclo de vida JSF

A imagem mostra todas as fases do ciclo de vida. No âmbito de validação e com o enfoque que vou dar nesse artigo, em especial três dessas fases vão nos interessar: Process Validations, Update Model Values e Invoke Application.

Vamos então imagina uma aplicação web qualquer onde precisamos cadastrar pessoas. Nessa aplicação iremos pedir que o usuário informe um nome e idade:

formulario

Para “processar” a tela acima, é mais do que natural que tenhamos mais dois artefatos. Um Managed Bean para tratar as requisicões e uma entidade que representa a pessoa:

my-managed-bean-pessoa

A Validação

Já indo ao ponto, vamos imaginar que no nosso sistema exista um requisito exigindo que o campo “idade” não possa receber valores negativos. Algo natural, já que ninguém pode ter “-43” anos. Por fins didáticos, vou desconsiderar a possibilidade de usar uma máscara/validação javascript no próprio browser. Não seria nada absurdo usar javascript, mas me ajudem aqui e vamos fingir que essa seria uma validação complexa demais para usar javascript 🙂

Nos resta então duas abordagens principais para validar a idade:

  1. No método “salvar” dentro do Managed Bean. (menos recomendado)
  2. Usar um validator JSF. (recomendado)

Fiz questão de usar os termos “menos recomendo” e “recomendado” para enfatizar que não é um crime fazer validações fora da fase de validação JSF. A necessidade de sair do “caminho feliz” sempre aparece. O crime seria fazer isso sem ter idéia do que está fazendo!

O porquê vem a seguir.

Assim Não

A maneira que classifiquei como “menos recomendada” seria validar o campo idade dentro do Managed Bean, na lógica do próprio método “salvar”. Quando o usuário clicar no botão “submeter”, o JSF invocaria o nosso método “salvar()” na fase Invoke Application:

metodo-salvar

E qual o problema afinal? Para entender é preciso saber o que ocorre em cada fase do ciclo de vida, e ter em mente que a fase Invoke Application acontece DEPOIS da fase Update Model Values. Resumindo, significa que o método “salvar()” só será invocado depois que o objeto Pessoa já teve o valor do seu atributo “idade” atualizado pelo JSF:

jsf-life-cycle-explained

Se você olhou a imagem acima deve ter percebido que no momento em que o método “salvar()” do Managed Bean é invocado, o JSF já setou um valor inconsistente “-14” no atributo “idade” do nosso modelo, o objeto Pessoa. Certo, e isso é problema? Pode ser sim. Deixar o modelo, que na maioria das vezes vai ser uma entidade gerenciada pelo JPA, inconsistente pode resultar em valores inválidos sendo gravados no banco de dados ou um erro. Na minha experiência, percebi que esse problema é mais comum de acontecer quando se usa “extended persistent contexts”, isto é, sessões JPA que sobrevivem por vários ciclos de request/response. Portanto quem usa o famigerado “contexto de conversação” do JBoss Seam, e agora CDI, está mais sujeito a ter problemas com esse tipo de validação “semanticamente incorreta”.

Agora Sim

A maneira ideal de fazer seria por meio de um JSF Validator. Observe que o foco não é criar uma classe separada do Managed Bean contendo a validação, e sim o fato da validação ocorrer na fase correta, Process Validations. As abordagens mais comuns seriam:

  1. Criar um validator, anotado com @FacesValidator.
  2. Criar um validation method dentro do próprio Managed Bean.

validators

Como já disse, o foco é validar na fase correta independente da maneira que for feita a validação. Ainda há outras maneiras de fazer a validação, por exemplo por meio de Bean Validation.

The End

É isso. Espero ter aberto a mente de quem vai começar a trabalhar com JSF ou então já trabalha mas não tinha essa percepção. Happy coding 🙂

10 thoughts on “JSF: Validação na fase correta

  1. Pingback: JSF: Validation at the right phase (understanding the life cycle) | Code to live. Live to code.

  2. Olá Rodrigo. Tudo bem?

    Entre as opções que você citou:

    Criar um validator, anotado com @FacesValidator.
    Criar um validation method dentro do próprio Managed Bean.

    Qual você recomendaria?

    • Oi Kelcio!
      O melhor vai depender da situação. Os validators são reaproveitados, então são ideais para os casos de validações que vão se repetir em várias telas diferentes. Exemplo clássico: validador de cpf.

      Um method validator acaba ficando para alguma validação singular que vc sabe que só vai ser usada na tela controlada por aquele managed bean específico. Validação que não será necessária em diferentes telas.

      Essa é a lógica que eu procuro seguir.

      Abraço!

      • Fala Rodrigo. Obrigado pela resposta.

        Tenho uma pequena aplicação utilizando Deltaspike que pretendo disponibilizar em breve, onde estou usando Hibernate Validator na entidade para validar CPF. E tenho uma classe de validação chamada CpfCadastradoValidator que valida se ja existe uma pessoa cadastrada com o CPF informado e barra a sequência do cadastro (não barra se o registro estiver sendo editado). Já para a funcionalidade de Alterar Senha eu tenho 2 campos: senha e confirmarSenha onde optei por usar um validator no Bean para validar se as senhas digitadas foram iguais. O que achou? Estou no caminho certo?

    • Oi de novo!:)

      Não sei exatamente como você implementou esse CpfCadastradoValidator, mas suponho que ele tem que ir no banco de dados para verificar se o CPF já existe lá. Sendo assim, eu não gosto da idéia de jsf validators acessando o banco. Então nesse caso eu trataria essa questão como regra de negócio mesmo (lógica de negócio na hora de gravar o registro), e não com um validador.

      Quanto a validação para confirmar senha, acho que usar o method validator dentro do bean é aceitável sim. Claro que por se tratar de validação em mais de um campo (cross field validation), existem outros desafios envolvidos. Talvez valha a pena você dá uma olhada no componente de cross validation do Omnifaces:
      http://showcase.omnifaces.org/validators/validateMultiple

      • Pois é, o CpfCadastradoValidator está funcionando como você descreveu. Vou tratar esses validadores como regra de negócio então. Vou dar uma olhada no Omnifaces também. Valeu pelas dicas!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s