Ответ 1
В этом случае я предлагаю написать специальный валидатор, который будет проверять на уровне класса (чтобы мы могли получить доступ к полям объекта), что одно поле требуется, только если другое поле имеет определенное значение. Обратите внимание, что вы должны написать общий валидатор, который получает 2 имени поля и работает только с этими двумя полями. Чтобы потребовать больше одного поля, вы должны добавить этот валидатор для каждого поля.
Используйте следующий код в качестве идеи (я его не тестировал).
-
Интерфейс проверки.
/** * Validates that field {@code dependFieldName} is not null if * field {@code fieldName} has value {@code fieldValue}. **/ @Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = NotNullIfAnotherFieldHasValueValidator.class) @Documented public @interface NotNullIfAnotherFieldHasValue { String fieldName(); String fieldValue(); String dependFieldName(); String message() default "{NotNullIfAnotherFieldHasValue.message}"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; @Target({TYPE, ANNOTATION_TYPE}) @Retention(RUNTIME) @Documented @interface List { NotNullIfAnotherFieldHasValue[] value(); } }
-
Реализация валидатора
/** * Implementation of {@link NotNullIfAnotherFieldHasValue} validator. **/ public class NotNullIfAnotherFieldHasValueValidator implements ConstraintValidator<NotNullIfAnotherFieldHasValue, Object> { private String fieldName; private String expectedFieldValue; private String dependFieldName; @Override public void initialize(NotNullIfAnotherFieldHasValue annotation) { fieldName = annotation.fieldName(); expectedFieldValue = annotation.fieldValue(); dependFieldName = annotation.dependFieldName(); } @Override public boolean isValid(Object value, ConstraintValidatorContext ctx) { if (value == null) { return true; } try { String fieldValue = BeanUtils.getProperty(value, fieldName); String dependFieldValue = BeanUtils.getProperty(value, dependFieldName); if (expectedFieldValue.equals(fieldValue) && dependFieldValue == null) { ctx.disableDefaultConstraintViolation(); ctx.buildConstraintViolationWithTemplate(ctx.getDefaultConstraintMessageTemplate()) .addNode(dependFieldName) .addConstraintViolation(); return false; } } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) { throw new RuntimeException(ex); } return true; } }
-
Пример использования валидатора
@NotNullIfAnotherFieldHasValue.List({ @NotNullIfAnotherFieldHasValue( fieldName = "status", fieldValue = "Canceled", dependFieldName = "fieldOne"), @NotNullIfAnotherFieldHasValue( fieldName = "status", fieldValue = "Canceled", dependFieldName = "fieldTwo") }) public class SampleBean { private String status; private String fieldOne; private String fieldTwo; // getters and setters omitted }
Обратите внимание, что реализация validator использует класс BeanUtils
из библиотеки commons-beanutils
, но вы также можете использовать BeanWrapperImpl
из Spring Framework.
См. также этот отличный ответ: Подтверждение перекрестного поля с помощью Hibernate Validator (JSR 303)