How to validate field level constraint before class level constraint?

后端 未结 2 1095
抹茶落季
抹茶落季 2021-01-06 23:36

I have a class:

@ColumnNameUnique(groups = CreateTableChecks.class)
public class Table {    
    @Valid
    @NotEmpty(groups = CreateTableChecks.class)
    p         


        
2条回答
  •  萌比男神i
    2021-01-06 23:57

    Instead of using @Hardy mentioned solution with @GroupSequence you can validate fields manually using reflection before your Validator.validate call.

    Method

    You can wrap this method

    /**
     * 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); }

    I prefer this approach since i do not want to to update all our entities and fields with group sequence annotations.

提交回复
热议问题