Подтверждение перекрестного поля с помощью HibernateValidator не отображает сообщений об ошибках

Я проверяю два поля: "пароль" и "confirmPassword" в форме равенства, используя HibernateValidator, как указано в этот ответ. Ниже приведен дескриптор ограничения (интерфейс валидатора).

package constraintdescriptor;

import constraintvalidator.FieldMatchValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

@Target({TYPE, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch
{
    String message() default "{constraintdescriptor.fieldmatch}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    /**
     * @return The first field
     */
    String first();

    /**
     * @return The second field
     */
    String second();

    /**
     * Defines several <code>@FieldMatch</code> annotations on the same element
     *
     * @see FieldMatch
     */
    @Target({TYPE, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Documented
    public @interface List{
        FieldMatch[] value();
    }
}

Ниже приведен валидатор ограничений (класс реализации).


package constraintvalidator;

import constraintdescriptor.FieldMatch;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.beanutils.BeanUtils;

public final class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object>
{
    private String firstFieldName;
    private String secondFieldName;

    public void initialize(final FieldMatch constraintAnnotation) {
        firstFieldName = constraintAnnotation.first();
        secondFieldName = constraintAnnotation.second();
        //System.out.println("firstFieldName = "+firstFieldName+"   secondFieldName = "+secondFieldName);
    }

    public boolean isValid(final Object value, final ConstraintValidatorContext cvc) {
        try {
            final Object firstObj = BeanUtils.getProperty(value, firstFieldName );
            final Object secondObj = BeanUtils.getProperty(value, secondFieldName );
            //System.out.println("firstObj = "+firstObj+"   secondObj = "+secondObj);
            return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
        }
        catch (final Exception e) {
            System.out.println(e.toString());
        }
        return true;
    }
}

Ниже приведен валидатор bean, который отображается на странице JSP (как указано commandName="tempBean" с тегом <form:form></form:form>).

package validatorbeans;

import constraintdescriptor.FieldMatch;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;

@FieldMatch.List({
    @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match", groups={TempBean.ValidationGroup.class})
})

public final class TempBean
{        
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.")
    private String password;
    @NotEmpty(groups={ValidationGroup.class}, message="Might not be left blank.")
    private String confirmPassword;

    public interface ValidationGroup {};

    //Getters and setters                
}

UPDATE

Все работает правильно и делает проверку правильной. Осталось только одно: отображать указанное сообщение об ошибке выше класса TempBean внутри @FieldMatch не отображается, т.е. только один вопрос:, как отображать сообщения об ошибках на странице JSP при нарушении проверки?

(аннотация @NotEmpty в обоих полях password и confirmPassword в классе TempBean работает и отображает указанные сообщения о нарушении, ничего не происходит с @FieldMatch).

Я использую группу проверки на основе этого вопроса, как указано в этот блог и он хорошо работает, не прерывая отображения сообщений об ошибках (как может показаться).


На странице JSP эти два поля указаны следующим образом.

<form:form id="mainForm" name="mainForm" method="post" action="Temp.htm" commandName="tempBean">

    <form:password path="password"/>
    <font style="color: red"><form:errors path="password"/></font><br/>

    <form:password path="confirmPassword"/>
    <font style="color: red"><form:errors path="confirmPassword"/></font><br/>

</form:form>

Ответ 1

Не могли бы вы попробовать использовать метод isValid? (это, безусловно, работает для меня в живом проекте):

 public boolean isValid(final Object value, final ConstraintValidatorContext cvc){
    boolean toReturn = false;

    try{
        final Object firstObj = BeanUtils.getProperty(value, firstFieldName );
        final Object secondObj = BeanUtils.getProperty(value, secondFieldName );

        //System.out.println("firstObj = "+firstObj+"   secondObj = "+secondObj);

        toReturn = firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
    }
    catch (final Exception e){
        System.out.println(e.toString());
    }
    //If the validation failed
    if(!toReturn) {
        cvc.disableDefaultConstraintViolation();
        //In the initialiaze method you get the errorMessage: constraintAnnotation.message();
        cvc.buildConstraintViolationWithTemplate(errorMessage).addNode(firstFieldName).addConstraintViolation();
    }
    return toReturn;
}

Также я вижу, что вы реализуете интерфейс ConstraintValidator с Object, буквально. Это должен быть объект поддержки, который у вас есть в вашей форме:

tempBean//тот, который вы указали в имени команды на самом деле.

Таким образом, реализация должна выглядеть так:

 implements ConstraintValidator<FieldMatch, TempBean>

Это, вероятно, не проблема здесь, но как будущая ссылка, вот как это должно быть.

UPDATE

Внутри интерфейса/аннотации FieldMatch у вас есть два метода: первый и второй, добавьте еще один вызов errorMessage, например:

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

/**
 * @return The first field
 */
String first();

/**
 * @return The second field
 */
String second();

/**
  @return the Error Message
 */
String errorMessage

Посмотрите в свой метод из класса Validation - вы получаете первое и второе имена полей там., поэтому просто добавьте errorMessage, например, это:

  private String firstFieldName;
  private String secondFieldName;
  //get the error message name
  private String errorMessagename; 
public void initialize(final FieldMatch constraintAnnotation)
{
    firstFieldName = constraintAnnotation.first();
    secondFieldName = constraintAnnotation.second();
    errorMessageNAme = constraintAnnotation.errorMessage(); 

    //System.out.println("firstFieldName = "+firstFieldName+"   secondFieldName = "+secondFieldName);
}

Внутри isValida получите его так же, как и для имени первого и второго полей и используйте его.