我有一个班级:
@ColumnNameUnique(groups = CreateTableChecks.class)
public class Table {
@Valid
@NotEmpty(groups = CreateTableChecks.class)
private List<Measure> measures;
}
类级别约束@ColumnNameUnique(groups = CreateTableChecks.class)
始终先运行,然后运行字段级别约束@NotEmpty(groups = CreateTableChecks.class)
。
无论如何强制首先运行字段级约束@NotEmpty(groups = CreateTableChecks.class)
?
答案 0 :(得分:2)
您需要使用@GroupSequence
和re-define the default group sequence。如果没有这个,组中的验证顺序就不会被定义,它可以是任何顺序(在你的情况下,总是首先执行类级别约束不是必须的)。这样的事情应该有效:
@GroupSequence({FieldChecks.class, ClassChecks.class})
@ColumnNameUnique(groups = ClassChecks.class)
public class Table {
@Valid
@NotEmpty(groups = FieldChecks.class)
private List<Measure> measures;
}
现在,如果@Default
组得到验证,首先会验证类级别约束,然后验证字段级别约束。
答案 1 :(得分:-1)
您可以在@GroupSequence
来电之前使用反射手动验证字段,而不是使用@Hardy提到的Validator.validate
解决方案。
方式强>
您可以包装此方法
/**
* Validates all single constrained fields of the given object and returns a
* set of {@link ConstraintViolation}. If <code>first</code> is
* <code>true</code> only the ConstraintViolation of the first invalid
* constraint is returned. <br>
* This method is useful to validate property constraints before class level
* constraints.
*
* @param validator
* @param object
* @param first Set to <code>true</code> if only the exceptions of the first
* invalid property shall be thrown
* @param groups
*/
public static Set<ConstraintViolation<Object>> 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<ConstraintViolation<Object>> 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 <code>first</code> is
* <code>true</code> only the ConstraintViolation of the first invalid
* constraint is thrown. <br>
* <br>
* 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 <code>true</code> 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<ConstraintViolation<Object>> cvs = validateProperties(validator, object, first,
groups);
if (!cvs.isEmpty())
throw new ConstraintViolationException(cvs);
}
我更喜欢这种方法,因为我不想用组序列注释更新所有实体和字段。