如何在类级别约束之前validation字段级别约束?

我上课了:

@ColumnNameUnique(groups = CreateTableChecks.class) public class Table { @Valid @NotEmpty(groups = CreateTableChecks.class) private List measures; } 
  • 类级别约束@ColumnNameUnique(groups = CreateTableChecks.class)始终先运行,之后运行字段级约束@NotEmpty(groups = CreateTableChecks.class)

  • 无论如何强制字段级约束@NotEmpty(groups = CreateTableChecks.class)先运行?

您需要使用@GroupSequence并重新定义默认组序列 。 如果没有这个,组中的validation顺序就不会被定义,它可以是任何顺序(在你的情况下,总是首先执行类级别约束不是必须的)。 像这样的东西应该工作:

 @GroupSequence({FieldChecks.class, ClassChecks.class}) @ColumnNameUnique(groups = ClassChecks.class) public class Table { @Valid @NotEmpty(groups = FieldChecks.class) private List measures; } 

现在,如果validation了@Default组,则首先validation类级别约束,然后validation字段级别约束。

您可以在Validator.validate调用之前使用reflection手动validation字段,而不是使用@Hardy提到的@GroupSequence解决方案。

方法

你可以包装这个方法

 /** * Validates all single constrained fields of the given object and returns a * set of {@link ConstraintViolation}. If first is * true only the ConstraintViolation of the first invalid * constraint is returned. 
* This method is useful to validate property constraints before class level * constraints. * * @param validator * @param object * @param first Set to true if only the exceptions of the first * invalid property shall be thrown * @param groups */ public static Set> validateProperties(final Validator validator, final Object object, final boolean first, final Class... groups) { if (object == null) throw new IllegalArgumentException("object must not be null."); if (validator == null) throw new IllegalArgumentException("validator must not be null."); final Set> cvs = new HashSet<>(); forFields: for (final Field field : ReflectionUtils.getAllFields(object.getClass(), null)) { final Annotation[] annotations = field.getDeclaredAnnotations(); boolean hasValidAnnotation = false; for (final Annotation annotation : annotations) { // single Constraint final Constraint constraint = annotation.annotationType().getAnnotation(Constraint.class); if (constraint != null) { cvs.addAll(validator.validateProperty(object, field.getName(), groups)); if (!cvs.isEmpty() && first) break forFields; } if (annotation.annotationType().equals(Valid.class)) hasValidAnnotation = true; } // nested validation if (hasValidAnnotation) { field.setAccessible(true); Object value = null; try { value = field.get(object); } catch (IllegalArgumentException | IllegalAccessException e) { // log } if (value != null) { cvs.addAll(validateProperties(validator, value, first, groups)); if (!cvs.isEmpty() && first) break; } } } return cvs; } /** * Validates all single constrained fields of the given object and throws a * {@link ConstraintViolationException}. If first is * true only the ConstraintViolation of the first invalid * constraint is thrown.
*
* This method is useful to validate property constraints before class level * constraints. * * https://hibernate.atlassian.net/browse/BVAL-557 * * @see #validateProperty(Validator, Object, String, Class...) * * @param validator * @param object * @param first Set to true if only the exceptions of the first * invalid property shall be thrown * @param groups * * @throws ConstraintViolationException */ public static void validatePropertiesThrow(final Validator validator, final Object object, final boolean first, final Class... groups) throws ConstraintViolationException { if (object == null) throw new IllegalArgumentException("object must not be null."); if (validator == null) throw new IllegalArgumentException("validator must not be null."); final Set> cvs = validateProperties(validator, object, first, groups); if (!cvs.isEmpty()) throw new ConstraintViolationException(cvs); }

我更喜欢这种方法,因为我不想用组序列注释更新所有实体和字段。