Вместо использования @Hardy упомянутого решения с @GroupSequence
вы можете проверить поля вручную, используя отражение перед вызовом 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);
}
Я предпочитаю такой подход, так как я не хочу, чтобы обновить все наши объекты и поля с аннотациями группы последовательностей.
Это поведение должно быть по умолчанию. Если простые поля не проверяются до того, как весь бит проверен, мы должны либо использовать обходной путь, как это, либо перепроверить поля в валидаторе классов (проверить свойства, уже отмеченные как '@ NotNull'). Боб никогда не может быть действительным, если проверка не выполняется в любом отдельном поле. – djmj
Я создал проблему на https://hibernate.atlassian.net/browse/BVAL-557. Единственное общее и практическое решение, которое я придумал, - это сначала проверять отдельные свойства, используя отражение, вместо того, чтобы добавлять это обходное решение ко всем нашим объектам. – djmj