自定义类级别约束的克罗斯验证不叫 [英] Custom Class Level Constraint for Crossfield validation not called

查看:146
本文介绍了自定义类级别约束的克罗斯验证不叫的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个验证克罗斯(JSR-303),与一流水平的自定义注释。然而,的isValid方法不叫(但是initialize方法)。

I am trying to implement a crossfield validation (JSR-303) with a custom annotation on class level. However the isValid method is not called (but the initialize method).

我的问题是:为什么的isValid方法没有被调用这个类级别验证?它界定物业水平的作品!

So my question is: Why is the isValid method not being called for this class level validator? Defining it on property level works!

我试了一下在JBoss AS 7和Websphere AS 8。

I tried it on JBoss AS 7 and Websphere AS 8.

下面是code和JUnit测试(工作)

Here is the code and a JUnit test (which works)

Test.java

public class Test {

@org.junit.Test
public void test() throws ParseException {
    Person person = new Person();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMDD");
    person.setPartyClosingDateFrom(new Date());
    person.setPartyClosingDateTo(sdf.parse("20120210"));
    Set<ConstraintViolation<Person>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(person);
    for(ConstraintViolation<Person> violation : violations) {
        System.out.println("Message:- " + violation.getMessage());
    }
}
  }

DateCompare.java

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

 @Target({ TYPE})
 @Retention(RUNTIME)
 @Constraint(validatedBy = DateCompareValidator.class)
 @Documented
 public @interface DateCompare {

/** First date. */
String firstDate();

/** Second date. */
String secondDate();

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

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

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

String message() default "totally wrong, dude!";

DateValidator.DateComparisonMode matchMode() default 
    DateValidator.DateComparisonMode.EQUAL;
 }

DateCompareValidator.java

 public class DateCompareValidator implements ConstraintValidator<DateCompare, Object>    {

/** describes the mode the validator should use**/
private DateValidator.DateComparisonMode comparisonMode;

/** The first date field name. */
private String firstDateFieldName;

/** The second date field name. */
private String secondDateFieldName;

/** the message to be used **/
private String messageKey = "failure";

/**
 * Initialize.
 * 
 * This method is used to set the parameters ans is REQUIRED even if you don't use any parameters
 * 
 * @param constraintAnnotation the constraint annotation
 */
@Override
public void initialize(final DateCompare constraintAnnotation) {
    this.comparisonMode = constraintAnnotation.matchMode();
    this.firstDateFieldName = constraintAnnotation.firstDate();
    this.secondDateFieldName = constraintAnnotation.secondDate();

}

/**
 * Checks if it is valid.
 * 
 * @param target the target
 * @param context the context
 * @return true, if is valid
 */
@Override
public boolean isValid(final Object target, final ConstraintValidatorContext context) {
    boolean isValid = true;

    final Date valueDate1 = DateCompareValidator.getPropertyValue(Date.class, this.firstDateFieldName, target);
    final Date valueDate2 = DateCompareValidator.getPropertyValue(Date.class, this.secondDateFieldName, target);
    if (isValid) {
        isValid = DateValidator.isValid(valueDate1, valueDate2, this.comparisonMode);
    } else {
        // at this point comparisonMode does not fit tp the result and we have to
        // design an error Message
        final ResourceBundle messageBundle = ResourceBundle.getBundle("resources.messages");
        final MessageFormat message = new MessageFormat(messageBundle.getString(this.messageKey));
        final Object[] messageArguments = { messageBundle.getString(this.messageKey + "." + this.comparisonMode) };

        // replace the default-message with the one we just created
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(message.format(messageArguments)).addConstraintViolation();
        isValid = false;
    }
    return isValid;
}


public static <T> T getPropertyValue(final Class<T> requiredType, final String propertyName, final Object instance) {
    if (requiredType == null) {
        throw new IllegalArgumentException("Invalid argument. requiredType must NOT be null!");
    }
    if (propertyName == null) {
        throw new IllegalArgumentException("Invalid argument. PropertyName must NOT be null!");
    }
    if (instance == null) {
        throw new IllegalArgumentException("Invalid argument. Object instance must NOT be null!");
    }
    T returnValue = null;
    try {
        final PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, instance.getClass());
        final Method readMethod = descriptor.getReadMethod();
        if (readMethod == null) {
            throw new IllegalStateException("Property '" + propertyName + "' of " + instance.getClass().getName()
                    + " is NOT readable!");
        }
        if (requiredType.isAssignableFrom(readMethod.getReturnType())) {
            try {
                final Object propertyValue = readMethod.invoke(instance);
                returnValue = requiredType.cast(propertyValue);
            } catch (final Exception e) {
                e.printStackTrace(); // unable to invoke readMethod
            }
        }
    } catch (final IntrospectionException e) {
        throw new IllegalArgumentException("Property '" + propertyName + "' is NOT defined in "
                + instance.getClass().getName() + "!", e);
    }
    return returnValue;
}

DateValidator.java

  public class DateValidator {

/**
 * The Enum DateComparisonMode.
 * 
 * Determins which Type of validation is used
 */
public enum DateComparisonMode {

    /** the given Date must be BEFORE the referenced Date */
    BEFORE,

    /** the given Date must be BEFORE_OR_EQUAL the referenced Date */
    BEFORE_OR_EQUAL,

    /** the given Date must be EQUAL the referenced Date */
    EQUAL,

    /** the given Date must be AFTER_OR_EQUAL the referenced Date */
    AFTER_OR_EQUAL,

    /** the given Date must be AFTER the referenced Date */
    AFTER;
}

/**
 * Compare 2 Date Values based on a given Comparison Mode.
 * 
 * @param baseDate the base date
 * @param valuationDate the valuation date
 * @param comparisonMode the comparison mode
 * @return true, if is valid
 */
public static boolean isValid(final Date baseDate, final Date valuationDate, final DateComparisonMode comparisonMode) {
    // Timevalue of both dates will be set to 00:00:0000
    final Date compValuationDate = DateValidator.convertDate(valuationDate);
    final Date compBaseDate = DateValidator.convertDate(baseDate);

    // compare the values
    final int result = compValuationDate.compareTo(compBaseDate);

    // match the result to the comparisonMode and return true
    // if rule is fulfilled
    switch (result) {
    case -1:
        if (comparisonMode == DateComparisonMode.BEFORE) {
            return true;
        }
        if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
            return true;
        }

        break;

    case 0:
        if (comparisonMode == DateComparisonMode.BEFORE_OR_EQUAL) {
            return true;
        }
        if (comparisonMode == DateComparisonMode.EQUAL) {
            return true;
        }
        if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
            return true;
        }
        break;

    case 1:
        if (comparisonMode == DateComparisonMode.AFTER) {
            return true;
        }
        if (comparisonMode == DateComparisonMode.AFTER_OR_EQUAL) {
            return true;
        }

        break;
    default:
        return false; // should not happen....
    }
    return false;
}

/**
 * Convert date.
 * 
 * sets the time Value of a given Date filed to 00:00:0000
 * 
 * @param t the t
 * @return the date
 */
private static Date convertDate(final Date t) {
    final Calendar calendar = Calendar.getInstance();
    calendar.setTime(t);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return (calendar.getTime());
}

特别是属性检索从这个帖子<一所href=\"http://stackoverflow.com/questions/1972933/cross-field-validation-with-hibernate-validator-jsr-303\">question

推荐答案

JSF 2.0不调用类级别的验证约束。
JSF验证

JSF 2.0 doesn't call class level validation constraints. From JSF validation:

JSF 2提供了内置的集成JSR-303限制。当你
  使用Bean验证您的应用程序,JSF将自动使用
  由 UIInput 引用值豆类的制约。

JSF 2 provides built-in integration with JSR-303 constraints. When you are using bean validation in your application, JSF automatically uses the constraints for beans that are referenced by UIInput values.

您必须手动调用它,或者你可以尝试的缝面其中有一个扩展&LT; F:validateBean&GT;

You have to call it manually, or you can try Seam Faces which has an extension <f:validateBean>

这篇关于自定义类级别约束的克罗斯验证不叫的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆