0

I've got a little problem here with my application. I'd like to check if fields password and confirm password match together, so I tried to do it like in the first answer for this question: Cross field validation with Hibernate Validator (JSR 303)

The problem is that it actually doesn't work and I HAVE NO IDEA WHY. Please, help me! This is my first post here, so please don't be too harsh for me.

Here's my Annotation :

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints;

import java.lang.annotation.*;
import javax.validation.Constraint;
import javax.validation.Payload;

/**
 *
 * @author lukasz
 */
@Documented
@Constraint(validatedBy = FieldMatchValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldMatch {

String message() default "{pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints.FieldMatch}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

String first();

String second();
}

Here's my ValidatorClass:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints;

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.beanutils.BeanUtils;

/**
 *
 * @author lukasz
 */
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {

    private String firstFieldName;
    private String secondFieldName;

    @Override
    public void initialize(FieldMatch constraintAnnotation) {
        firstFieldName = constraintAnnotation.first();
        secondFieldName = constraintAnnotation.second();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        try {
            String sFirstField = BeanUtils.getProperty(value, firstFieldName);
            String sSecondField = BeanUtils.getProperty(value, secondFieldName);
            if(sFirstField.equals(sSecondField)){
                return true;
            }
        } catch (IllegalAccessException ex) {
            Logger.getLogger(FieldMatchValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvocationTargetException ex) {
        Logger.getLogger(FieldMatchValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchMethodException ex) {
        Logger.getLogger(FieldMatchValidator.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
}

And here's my bean:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pl.lodz.p.zsk.ssbd2012.ssbd12.Beans;

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints.CheckEmail;
import pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints.FieldMatch;
import pl.lodz.p.zsk.ssbd2012.ssbd12.entities.Account;
import pl.lodz.p.zsk.ssbd2012.ssbd12.mok.endpoint.MokEndpointLocal;

/**
 *
 * @author krzys
 * @author lukasz
 */

@ManagedBean
@RequestScoped
@FieldMatch(first = "password", second = "password2", message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.ValidationConstraints.FieldMatch}")
public class RegisterBean {

    /**
     * Creates a new instance of RegisterBean
     */

    @EJB
    MokEndpointLocal endpoint;

    @Size(min = 3, max = 16, message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.login.size}")
    @Pattern(regexp = "[a-zA-Z0-9]+", message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.login.invalid}")
    private String login;

    @Size(min = 6, max = 64, message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.password.size}")
    @Pattern(regexp = "[a-zA-Z0-9]+", message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.password.invalid}")
    private String password;

    private String password2;

    @Pattern(regexp = "[A-Ż][a-ż]+", message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.name.invalid}")
    private String name;

    @Pattern(regexp = "[A-Ż][a-ż]+", message = "{pl.lodz.p.zsk.ssbd2012.ssbd12.Beans.RegisterBean.surname.invalid}")
    private String surname;

    @CheckEmail
    private String email = "";


    /**
     * @return the login
     */
    public String getLogin() {
        return login;
    }

    /**
     * @param login the login to set
     */
    public void setLogin(String login) {
        this.login = login;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    public String getPassword2() {
        return password2;
    }

    public void setPassword2(String password2) {
        this.password2 = password2;
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String register ()
    {
//       Account account = new Account();
//       account.setLogin(login);
//       account.setHaslo(password);
//       account.setImie(name);
//       account.setNazwisko(surname);
//       account.setEmail(email);
//       endpoint.register(account);
       return "registerSucces";
    }

    /**
     * @return the surname
     */
    public String getSurname() {
        return surname;
    }

    /**
     * @param surname the surname to set
     */
    public void setSurname(String surname) {
        this.surname = surname;
    }
}

And here's JSF:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core">
<h:head>
    <h:outputStylesheet name="menu.css" library="css" />
    <title>#{messages.registration}</title>
</h:head>

<h:body>
    <ui:composition template="./../resources/mainTemplate.xhtml">

        <h4>#{messages.registration}</h4>
    <ui:define name="content">
        <h4>#{messages.registration}</h4>
        <h1>#{messages.registrationInfo1}</h1>
    #{messages.registrationInfo2}
    <h:form>
        <h2>
            <h:outputText value="#{messages.loginForm}"/>
            <h:inputText id="login" value="#{registerBean.login}" />  
        </h2>
        <h2>
            <h:outputText value="#{messages.passwordForm}" />
            <h:inputSecret id="password" value="#{registerBean.password}" />
        </h2>
        <h2>
            <h:outputText value="#{messages.repeatPasswordForm}"/> 
            <h:inputSecret id="confirm" value="#{registerBean.password2}" />
        </h2>
        <h2>
            <h:outputText value="#{messages.nameForm}"/>
            <h:inputText id="name" value="#{registerBean.name}" />
        </h2>
        <h2>
            <h:outputText value="#{messages.surnameForm}"/>
            <h:inputText id="surname" value="#{registerBean.surname}" />
        </h2>
        <h2>
            <h:outputText value="#{messages.emailForm}"/>
            <h:inputText id="email" value="#{registerBean.email}" />
        </h2>
        <h2>    
            <h:commandButton value="#{messages.send}" action="#{registerBean.register()}" />
        </h2>
    </h:form>
    </ui:define>
    </ui:composition>
</h:body>
</html>
Community
  • 1
  • 1
gadzix90
  • 744
  • 2
  • 13
  • 28
  • In your case who should trigger validation? To run validation on bean somebody should create `Validator`, call `validate()` method and pass your object to it. If your framework doesn't do it, so you should do it yourself. – Slava Semushin Aug 15 '12 at 19:15
  • I'm not sure but I thought that annotation is just enough, cause other annotations like Pattern or CheckEmail(which I made myself too) work just fine. Correct me if I'm wrong. – gadzix90 Aug 15 '12 at 20:54

1 Answers1

5

Class-level constraints are not triggered automatically by JSF during validation phase. You can use only field-level constraints (moreover not all fields are valuated by JSF but only those that are in your facelet).

If you want to use bean validation you can perform validation manually:

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Test>> violations = validator.validate( this, Default.class );

You can do it in registration method of your bean or after update model phase (but I've never tried it).

Anyway you can use JSF validation instead of bean validation or check the passwords directly in the registration method:

public String registration() {
    ...

    if ( !password.equals(password2) ) {
        FacesContext.getCurrentInstance().addMessage( null, new FacesMessage( "Passwords do not match" ) );
        return null;
    }

    ...
}
Alf
  • 2,291
  • 1
  • 28
  • 34
  • Ok, I see now what's the reason but I still don't know how to solve the problem. Your advice is too wide - I mean I would appreciate an example, cause now I don't know what exactly should I do. Should I do some changes in JSF code? You said I have to create Validator class and call validate() - so whats with the FieldMatch and FieldMatchValidator? Are they no longer required? And how should I call validate() method of Validator class? – gadzix90 Aug 16 '12 at 17:01
  • @user1591434 See my update. Keep in mind that bean validation is a generic validation system that can be used everywhere in java. JSF has some facilities that help you to avoid some boilerplate code like manual validation I suggested you in my update. However these facilities are restricted to field-level validation. If you want class-level validation you must do it manually, as far as I know. – Alf Aug 16 '12 at 18:59