2 de março de 2011

JavaEE 6: Bean Validation 1.0

A especificação do JEE 6, criou uma validação padrão para os JavaBeans, que foi o Bean Validation 1.0. O que isso faz? bom.. a partir de anotações na classe de modelo, você consegue validar campos numéricos, definir se datas informadas serão obrigatoriamente maiores ou menores que a data atual, se o campo pode ser vazio ou não, assim ao dar o submit no form ele já valida esses campos, não precisando submeter os valores e verificar um a um no bean antes de fazer qualquer operação, outro detalhe interessante dessas anotações é que todas elas tem a propriedade message que é recebido pela tag <h:message> do JSF... para facilitar vou dizer o que cada anotação faz, e depois mostrar um exemplo com todas as anotações, vamos lá:
@AssertFalse: Obriga que valores booleanos sejam falsos;
@AssertTrue: Obriga que valores booleanos sejam verdadeiros;
@DecimalMax: Os valores decimais devem ser menores ou iguais ao definido na propriedade value;
@DecimalMin: Os valores decimais devem ser maiores ou iguais ao definido na propriedade value;
@Digits: Define o intervalo de um decimal, a propriedade integer diz respeito a quantidade de números inteiros, e a fraction define quantas casas após a vírgula;
@Future: Anotação para datas futuras, a data deve ser uma data futura, maior que a data atual;
@Max: Anotação para inteiros, define que o valor seja inferior ou igual ao valor definido no value;
@Min: Anotação para inteiros, define que o valor seja superior ou igual ao valor definido no value;
@NotNull: O valor para o campo que recebe essa anotação não pode ser nulo;
@Null: O valor para o campo que recebe essa anotação pode ser nulo;
@Past: Anotação para datas passadas, a data deve ser uma data passada ou a data atual;
@Pattern: O valor desse campo deve corresponder à expressão regular definida na propriedade regexp;
@Size: Esta anotação pode ser usada para String, Collection ou arrays. Caso seja String, esta deverá ter a quantidade mínima de caracteres definidas na propriedade min e a quantidade máxima definida com o max. No caso de Collection/array é avaliado a quantidade mínima e máxima de elementos. Obs: pode ser usado a propriedade min ou max separadas, ou seja, pode-se definir apenas que seja validado a quantidade mínima de alguma coisa ou apenas a quantidade máxima.

TESTE:
Vamos ao projeto de teste: no NetBeans crie uma  Aplicação Web com o nome de BeanValidation.
Dentro do pacotes de código-fonte, crie os pacotes model e controle, agora no model crie uma classe java com o nome de Objeto.java com o seguinte código:
public class Objeto {

    @AssertFalse(message="Este campo precisa ser falso")
    private boolean isFalso;

    @AssertTrue(message="Este campo precisa ser verdadeiro")
    private boolean isVerdadeiro;

    @NotNull(message="Data não pode ser nula")
    @Future(message="Data precisa ser maior que a data atual")
    private Date eventoFuturo;

    @Past(message="Data precisa ser menor ou igual que a data atual")
    private Date dataNascimento;

    @Max(value=100, message="Quantidade Max: não pode ultrapassar 100 unidades")
    private int quantidadeMax;

    @Min(value=10, message="Quantidade Min: não pode ser abaixo de 10 unidades")
    private int quantidadeMin;

    @DecimalMax(value="30.00", message="Desconto Max: precisa ser abaixo de 30.00")
    private BigDecimal descontoMaximo;

    @DecimalMin(value="1.50", message="Juro Min: precisa ser acima de 1.50")
    private BigDecimal juroMinimo;

    @Digits(integer=3, fraction=2, message="Preço: apenas centenas e 2 casas após o ponto")
    private BigDecimal preco;

    @Null(message="Apelido: campo pode ser nulo")//Utilizar em combos
    private String apelido;

    @Pattern(regexp = "\\(\\d{3}\\)\\d{4}-\\d{4}", message="Telefone: preencha no formato (XXX)XXXX-XXXX")
    private String telefone;

    @NotNull
    @Size(min = 2, max = 200, message="Descrição: tamanho mínimo de 2 e máximo de 200")
    private String descricao;

    //getters e setters
}
Obs: todas as anotações são importadas do pacote javax.validation.constraints. 
Agora no pacote controle crie uma nova classe java para ser nosso bean de comunicação com o JSF, com o nome de ObjetoBean.java, segue o código:
@Named
@RequestScoped
public class ObjetoBean {

    private Objeto objeto = new Objeto();

    public String salvar(){
        return "sucesso";
    }

    public Objeto getObjeto() {
        return objeto;
    }

    public void setObjeto(Objeto objeto) {
        this.objeto = objeto;
    }
}
Agora reaproveitanto a página index.xhtml que é criada juntamente com o projeto, vamos montar nosso form com todos os campos a serem validados, segue o código que deve estar dentro do < h:body >:
<h:body>
    <h:form>
        <h:panelgrid columns="3">
            <h:outputtext value="Check False" />
            <h:selectbooleancheckbox id="checkFalse" value="#{objetoBean.objeto.isFalso}" />
            <h:message for="checkFalse" />

            <h:outputtext value="Check True" />
            <h:selectbooleancheckbox id="checkTrue" value="#{objetoBean.objeto.isVerdadeiro}" />
            <h:message for="checkTrue" />

            <h:outputtext value="Evento Futuro:" />
            <h:inputtext id="eventoFuturo" value="#{objetoBean.objeto.eventoFuturo}" />
                <f:convertdatetime pattern="dd/MM/yyyy" />
            </h:inputtext>
            <h:message for="eventoFuturo" />

            <h:outputtext value="Data Nascimento:" />
            <h:inputtext id="dataNascimento" value="#{objetoBean.objeto.dataNascimento}" />
                <f:convertdatetime pattern="dd/MM/yyyy" />
            </h:inputtext>
            <h:message for="dataNascimento" />

            <h:outputtext value="Quantidade Max:" />
            <h:inputtext id="qtdMax" value="#{objetoBean.objeto.quantidadeMax}" />
            <h:message for="qtdMax" />

            <h:outputtext value="Quantidade Min:" />
            <h:inputtext id="qtdMin" value="#{objetoBean.objeto.quantidadeMin}" />
            <h:message for="qtdMin" />

            <h:outputtext value="Desconto Max:" />
            <h:inputtext id="descontoMax" value="#{objetoBean.objeto.descontoMaximo}" />
            <h:message for="descontoMax" />

            <h:outputtext value="Juro Min:" />
            <h:inputtext id="juroMin" value="#{objetoBean.objeto.juroMinimo}" />
            <h:message for="juroMin" />

            <h:outputtext value="Preço:" />
            <h:inputtext id="preco" value="#{objetoBean.objeto.preco}" />
            <h:message for="preco" />

            <h:outputtext value="Telefone:" />
            <h:inputtext id="telefone" value="#{objetoBean.objeto.telefone}" />
            <h:message for="telefone" />

            <h:outputtext value="Descrição:" />
            <h:inputtext id="descricao" value="#{objetoBean.objeto.descricao}" />
            <h:message for="descricao" />

        </h:panelgrid>
        <h:commandbutton action="#{objetoBean.salvar}" value="Testar" />
    </h:form>
</h:body>

E crie uma página JSF com o nome de sucesso.xhtml que será para onde seremos redirecionados quando todos os campos validados estejam corretos. Código:
<h:body>
    <h:form>
        Valores informados com sucesso!
        <h:commandButton value="Testar novamente" action="index" />
    </h:form>
</h:body>

Segue abaixo a imagem da página index, com os valores fora dos limites estipulados nas anotações:


E agora a janela com os valores corretos, que passam pela validação:


Eu particularmente achei muito util essas anotações, já que não sou muito adepta de testar valores nos métodos do bean. :)

13 comentários:

  1. Opa acabei de ver o link no guj, parabens e obrigado me ajudou muito

    ResponderExcluir
  2. Olá! Obrigada, fico feliz ter ajudado :)

    ResponderExcluir
  3. Olá! Provavelmente o TomCat7 não tem as bibliotecas necessárias para funcionar o Bean Validation, para isso você vai ter que baixar os jar, e adicionar ao projeto, não testei, mas encontrei os imports dentro desse jar: http://mirrors.ibiblio.org/pub/mirrors/maven2/org/apache/geronimo/specs/geronimo-validation_1.0_spec/1.0-CR5/geronimo-validation_1.0_spec-1.0-CR5.jar
    Aguardo retorno, pra saber se deu certo ou não.

    ResponderExcluir
  4. Bom exemplo, porém como fazer ele funcionar com o Tomcat 7.0.11 ?

    ResponderExcluir
  5. Então, eu até tinha respondido a uns dias atrás mas o blogger fez uma atualização e removeu o meu comentário. Não testei, mas pelo o que eu vi, esse .jar tem todas os imports para essas anotações: http://www.findjar.com/jar/org/apache/geronimo/specs/geronimo-validation_1.0_spec/1.0-CR5/geronimo-validation_1.0_spec-1.0-CR5.jar.html

    ResponderExcluir
  6. Não tem validação para String vazia?

    ResponderExcluir
  7. In order for the Bean Validation model to work as intended, you must set the context parameter javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL to true in the web deployment descriptor file, web.xml:



    javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL

    true

    This parameter enables the JavaServer Faces implementation to treat empty strings as null.

    ResponderExcluir
  8. Olá Fernando! Grata por sua contribuição.
    O Hibernate Validator tem para Strings:
    org.hibernate.validator.NotEmpty

    ResponderExcluir
  9. Muito bom este post. Só vejo um problema de colocar mensagem de validação dentro da classe "model", internacionalização. Tentei, mas não consegui uma forma de obter esta mensagem do message Bundle dentro do model.

    Tem alguma solução pra isso?

    ResponderExcluir
    Respostas
    1. vc está fazendo a configuração pelo faces-config.xml?
      Dessa forma:


      <application>
      <locale-config>
      <default-locale>pt_BR</default-locale>
      <message-bundle>br.com.javasemcafe.propriedades.JSF_Messages_pt_BR</message-bundle>
      </locale-config>
      </application>

      Excluir
  10. Excelente post!
    Realmente o Tomcat 7 não possui as bibliotecas. Só foi possível utilizar as annotations depois de importar o geronimo-validation_1.0_spec-1.0-CR5 do link (http://www.findjar.com/jar/org/apache/geronimo/specs/geronimo-validation_1.0_spec/1.0-CR5/geronimo-validation_1.0_spec-1.0-CR5.jar.html) que você indicou.

    ResponderExcluir
  11. Boa tarde, parabéns pelo blog, ajuda muito... Tentei fazer o exemplo mas ao clicar no botão testar, aparece a página com o seguinte erro "Could not create Configuration." Alguém sabe me dizer como corrigir? Obrigado

    ResponderExcluir

Deixe seu comentário... ;)