1
votes

I am working on an application using JSF 2.1 and PrimeFaces 3.2, server Tomcat 7. Right now, I am working on form to register new users. The problem is in converter.

I use few standard fields and two of them are passwords. I have custom data type for password, so I want to use converter to convert String data from field to Password variable in a bean. Primefaces forms use AJAX after submit, and there is probably the problem. If I fill in the form completely, without validation errors, everything works fine. But if there is a validaton error and no converter error (I check for the password length in the converter), whole form stops working at all. I have to refresh page to have it working again.

Here are some sources:

Password class:

public class Password {

    public static final short MIN_LENGTH = 5;

    private String text;
    private String hash;

    public Password(String text) {
        this.text = text;
        this.hash = Hasher.sha512(text);
    }

    /**
     * Get password instance with known hash only
     * @param hash SHA-512 hash
     * @return Password instance
     */
    public static Password getFromHash(String hash) {
        Password password = new Password(null);
        password.hash = hash;
        return password;
    }



    @Override
    public int hashCode() {
        return hash.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Password other = (Password) obj;
        if ((this.hash == null) ? (other.hash != null) : !this.hash.equals(other.hash)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return hash;
    }

    /**
     * @return the text
     */
    public String getText() {
        return text;
    }
}

Password converter:

@FacesConverter(forClass = Password.class)
public class PasswordConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        String text = (String) value;

        if (text.length() >= Password.MIN_LENGTH) {
            return new Password(text);
        }

        FacesMessage msg = new FacesMessage(Texter.get("forms/forms", "shortPassword").replace("%limit%", String.valueOf(Password.MIN_LENGTH)));
        msg.setSeverity(FacesMessage.SEVERITY_ERROR);
        throw new ConverterException(msg);
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        try {
            Password password = (Password) value;
            return password.getText();
        } catch (Exception ex) {
            throw new ConverterException(ex);
        }
    }
}

The form in facelet:

<h:form id="registration">
    <p:panelGrid columns="3">

        <h:outputLabel value="#{commonTxt.email}:" for="email" />
        <p:inputText id="email" value="#{userRegistrationForm.email}" required="true" requiredMessage="#{formsTxt.msgEmpty}">
            <f:validator validatorId="email" />

            <f:validator validatorId="unique" />
            <f:attribute name="entity" value="SystemUser" />
            <f:attribute name="field" value="email" />
            <f:attribute name="uniqueMessage" value="#{formsTxt.nonUniqueEmail}" />
        </p:inputText>
        <p:message for="email" />

        <h:outputLabel value="#{usersTxt.password}:" for="password" />
        <p:password id="password" value="#{userRegistrationForm.password}" binding="#{password}" autocomplete="off" feedback="true" weakLabel="#{formsTxt.passwordWeak}" goodLabel="#{formsTxt.passwordGood}" strongLabel="#{formsTxt.passwordStrong}" promptLabel="#{formsTxt.passwordPrompt}" />
        <p:message for="password" />

        <h:outputLabel value="#{usersTxt.passwordCheck}:" for="passwordCheck" />
        <p:password id="passwordCheck" value="#{userRegistrationForm.passwordCheck}" binding="#{passwordCheckInput}" autocomplete="off">
            <f:validator validatorId="match" />
            <f:attribute name="matchAgainst" value="#{password}" />
            <f:attribute name="matchMessage" value="#{formsTxt.passwordMismatch}" />
        </p:password>
        <p:message for="passwordCheck" />

        <p:column /><p:column /><p:column />

        <h:outputLabel value="#{usersTxt.name}:" for="name" />
        <p:inputText id="name" value="#{userRegistrationForm.name}" maxlength="255" required="true" requiredMessage="#{formsTxt.msgEmpty}" />
        <p:message for="name" />


        <f:facet name="footer">
            <p:commandButton value="#{usersTxt.register}" action="#{userRegistrationForm.register()}" update="registration" />
        </f:facet>
    </p:panelGrid>
</h:form>

I won't post code of the bean #{userRegistrationForm}, there are two Passwords properties with getters and setters.

Any help leading to solution of my problem appreciated. Thanks in advance.

1

1 Answers

1
votes

Solved! I just used FacesContext.getCurrentInstance().isValidationFailed() to see if the validation failed or not. In case of failure, the converter now returns null (the conversion won't be done), in other case the converter will return proper object. And the form works fine with the conversion working.