Java 未调用用于交叉字段验证的自定义类级别约束

Java 未调用用于交叉字段验证的自定义类级别约束,java,jsf-2,annotations,bean-validation,Java,Jsf 2,Annotations,Bean Validation,我试图在类级别上使用自定义注释实现跨域验证(JSR-303)。但是,不会调用isValid方法(而是initialize方法) 所以我的问题是:为什么没有为这个类级验证器调用isValid方法?在属性级别定义它很有效 我在JBossAS7和WebSphereAS8上进行了尝试 下面是代码和JUnit测试(有效) Test.java public class Test { @org.junit.Test public void test() throws ParseException {

我试图在类级别上使用自定义注释实现跨域验证(JSR-303)。但是,不会调用isValid方法(而是initialize方法)

所以我的问题是:为什么没有为这个类级验证器调用isValid方法?在属性级别定义它很有效

我在JBossAS7和WebSphereAS8上进行了尝试

下面是代码和JUnit测试(有效)

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());
    }
}
  }
 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;
 }
 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;
}
  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());
}

特别是属性检索取自本文

jsf2.0不调用类级验证约束。 发件人:

JSF2提供了与JSR-303约束的内置集成。当你 如果在应用程序中使用bean验证,JSF会自动使用
UIInput
值引用的bean约束


您必须手动调用它,或者您可以尝试使用richfaces提供的扩展名

,也可以使用它。无论如何,我都不知道如何使用它,感谢您对标准的澄清我很抱歉,我的意思是您可以使用
进行跨域验证,就像