6 Replies Latest reply: Sep 14, 2009 4:49 PM by Dmitry Trunikov RSS

Seam Validation losing state

Luciano Molinari Newbie
Good Morning,

I have a little application using Seam and until now all my validations had been done directly by hibernate validator using anotations in my entities. Now i need to do a validation programatically in the Action. When the error occours, the error message is displayed correctly, but it loses the data informed by the user in the form. When occours some simple validation error (@NotNull for example) it comes back to the form with the data filled correctly, the problem is with the manual validation.

My form on xhtml looks like this



`

                <h:form id="formUsuario" styleClass="edit">
                        <s:validateAll>
                                <rich:panel>
                                        <f:facet name="header">
                                                <h:outputText value="#{messages[usuarioAction.keyLabelAct]}" />
                                        </f:facet>
                                       
                                        <s:decorate id="loginField" template="../layout/edit.xhtml">
                                                <ui:define name="label">#{messages['label.login']}</ui:define>
                                                <h:inputText value="#{usuarioAction.usuario.login}" id="txtLogin" required="true" size="15" />
                                        </s:decorate>
                                       
                                        <s:decorate id="nomeField" template="../layout/edit.xhtml">
                                                <ui:define name="label">#{messages['label.nome']}</ui:define>
                                                <h:inputText value="#{usuarioAction.usuario.nome}" id="txtNome" required="true" size="30" />
                                        </s:decorate>
                                       
                                        <s:decorate id="perfilField" template="../layout/edit.xhtml">
                                                <ui:define name="label">#{messages['label.perfil']}</ui:define>
                                                <h:selectOneMenu id="selectPerfil" value="#{usuarioAction.usuario.perfil}" required="true"
                                                        converter="#{usuarioAction.converterPerfil}">
                                                        <s:selectItems var="perfil" value="#{usuarioAction.perfis}" label="#{perfil.nome}"
                                                                noSelectionLabel="#{messages['label.selecione']}"/>                                         
                                                </h:selectOneMenu>
                                        </s:decorate>
                                       
                                        <div style="clear:both">
                                                <span class="required">*</span>
                                                #{messages['label.camposObrigatorios']}
                                        </div>
                               
                                </rich:panel>
                               
                                <div class="actionButtons">
                                        <h:commandButton action="#{usuarioAction.add}" id="btnAdd" value="#{messages['label.incluir']}"
                                                rendered="#{usuarioAction.act eq 'incluir'}"/>
                                        <h:commandButton action="#{usuarioAction.update}" id="btnUpdate" value="#{messages['label.alterar']}"
                                                rendered="#{usuarioAction.act eq 'alterar'}"/>
                                        <h:commandButton action="#{usuarioAction.remove}" id="btnRemove" value="#{messages['label.excluir']}"
                                                rendered="#{usuarioAction.act eq 'excluir'}"/>
                                        <s:button view="/usuario/list.xhtml" value="#{messages['label.cancelar']}" id="btnCancel" propagation="end"/>
                                </div>
                               
                        </s:validateAll>
                </h:form>
...
`

My Action:
`...
@Name("usuarioAction")
public class UsuarioAction extends BaseAction {

        private Usuario usuario = new Usuario();
       
        @In("#{usuarioService}")
        private UsuarioService usuarioService;
       
        @In("#{perfilService}")
        private PerfilService perfilService;
       
        @In
        private FacesMessages facesMessages;
       
        private EntidadeComIdConverter<Perfil> converterPerfil;
       
        private List<Perfil> perfis;
       
        @Begin(join = true)
        public String loadUsuario() {
                if(usuario != null && usuario.getIdUsuario() != null &&
                                (getAct().equals(ACTION_ALTERAR) || getAct().equals(ACTION_EXCLUIR))) {
                        usuario = usuarioService.findById(usuario.getIdUsuario());
                        if(usuario == null) {
                                facesMessages.add(FacesMessage.SEVERITY_ERROR, "#{messages['label.usuario.naoEncontrado']}");
                                return NOT_FOUND;
                        }
                } else {
                        usuario = new Usuario();
                }
                return SUCCESS;
        }
       
        @End
        public String add() {
                if(usuarioService.existeUsuarioComLogin(usuario.getLogin())) {
                        facesMessages.addToControl("txtLogin", "#{messages['erro.existe.usuario.login']}");
                        return null;
                }
               
                usuarioService.add(usuario);
                facesMessages.add("#{messages['label.usuario.inserido']}");
                usuario = new Usuario();
                return SUCCESS;
        }
..
`

My navigation rules:   

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://jboss.com/products/seam/pages"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd">
   
    <param name="idUsuario" value="#{usuarioAction.usuario.idUsuario}"/>
    <param name="act" value="#{usuarioAction.act}"/>
    <action execute="#{usuarioAction.loadUsuario}"/>
       
        <navigation>
                <rule if-outcome="notFound">
                        <redirect view-id="/usuario/list.xhtml"/>
                </rule>          
        </navigation>
       
        <navigation from-action="#{usuarioAction.add}">
                <rule if-outcome="success">
                        <redirect view-id="/usuario/list.xhtml"/>                
                </rule>
        </navigation>
       
        <navigation from-action="#{usuarioAction.update}">
                <redirect view-id="/usuario/list.xhtml"/>
        </navigation>    
 
        <navigation from-action="#{usuarioAction.remove}">
                <redirect view-id="/usuario/list.xhtml"/>
        </navigation>     
       
</page>


Can someone figure out what can be causing the problem?I've already tried many thins, but no success.
Thanks,
Luciano

Ps.: Sorry for the english and for the text formating.
  • 1. Re: Seam Validation losing state
    Shervin Asgari Master

    I dont see any custom validators.


    for instance:




    @Name("validator")
    @BypassInterceptors
    public class Validator {
    
         private String datePattern;
    
         /**
          * Validates a date. Will *not* do any conversion. Takes a string
          * 
          * @param context
          * @param toValidate
          * @param value
          */
         public void date(FacesContext context, UIComponent toValidate, Object value) {
              String val = (String) value;
              SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
              Date nDate;
              try {
                   nDate = sdf.parse(val);
                   if (nDate.after(new Date())) {
                        ((UIInput) toValidate).setValid(false);
                        FacesMessages.instance().addToControlFromResourceBundle(toValidate.getId(), "future.date", datePattern);
                   }
              } catch (ParseException ex) {
                   ((UIInput) toValidate).setValid(false);
                   FacesMessages.instance().addToControlFromResourceBundle(toValidate.getId(), "invalid.date", datePattern);
              }
    
         }
    }
    



    And in your xhtml just add the validator on the inputtextfield you want to validate ie:



    <h:inputText value="#{mybean.date}" required="true" validator="#{validator.date}" immediate="true"/>




    That should work. If this still doesnt work, its because you to set higher scope on your component. Default scope is event, thus it will loose after render response. Try PAGE scope or higher.

  • 2. Re: Seam Validation losing state
    Luciano Molinari Newbie
    Hi Shervin,

    Thanks for your answer. There's a custom validation on method add of the class UsuarioAction.

    @End
    public String add() {
        if(userService.existsUserWithLogin(user.getLogin())) {
            facesMessages.addToControl("txtLogin", "#{messages['erro.existe.usuario.login']}");
            return null;
        }
        usuerService.add(user);
        facesMessages.add("#{messages['label.usuario.inserido']}");
        usuario = new Usuario();
        return SUCCESS;
    }

    I've already tried to change the class scope to PAGE and SESSION, but the problem persists. I'll also try to use your solution.


  • 3. Re: Seam Validation losing state
    Dmitry Trunikov Newbie

    I'm not sure but it seems that immediate cause of the issue is an annotation @End at the method add().
    That method ends conversation in any case either success or failure.
    Hope this will help you.


    P.S. From my point of view the best place for conversation management directives is *.page.xml files.

  • 4. Re: Seam Validation losing state
    Luciano Molinari Newbie
    Hi Dmitry,

    In the Seam docs (http://docs.jboss.org/seam/2.0.2.GA/reference/en-US/html_single/#end-annotation) it says:
    "Specifies that a long-running conversation ends when this method returns a non-null outcome without exception."

    As my method is returning null when the validation error occours, it shouldn't be ending the conversation. Anyway, i'll try do it using the *page.xml instead of the annotations.

    Thanks,
    Luciano
  • 5. Re: Seam Validation losing state
    Shervin Asgari Master

    Dmitry Trunikov wrote on Sep 14, 2009 08:21:


    P.S. From my point of view the best place for conversation management directives is *.page.xml files.


    I disagree. I think it is much more readable to have these stuff on the java code, instead of toggling back and forth on pages.xml


  • 6. Re: Seam Validation losing state
    Dmitry Trunikov Newbie

    Shervin Asgari wrote on Sep 14, 2009 14:41:

    I disagree. I think it is much more readable to have these stuff on the java code, instead of toggling back and forth on pages.xml


    Tastes differ ;)
    I can see one big advantage in conversation management through page.xml.
    In the development mode we can easily change conversation's behaviour  without code change and application redeploying. It is very handy feature especially for newcomers of the Seam as they have a chance to play with conversations.
    The second point (just my opinion) is that conversation has more relation to navigation than to code.