You can define a custom hibernate validator to do cross-field checking.
Based on your class, you can see the following code on how to implement such a custom validator.
In summary, we need to:
- Add the hibernate-validator dependency in the pom file
- Define an annotation using the @interface keyword.
- Implement the interface we coded in step 2.
- Add the constraint to the domain class.
Note, I have set the validator to be a class-level validator, not a single field validator. I chose this because if the validation fails, it could be that either the max value or the min value is wrong, but we (probably) can't know which.
I provide a summary, and for more information I would refer you to the official hibernate validator documentation.
Adding the dependency in the pom file:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.2.0.Final</version>
</dependency>
Defining the annotation:
Here, settings define 1) that the validator will be applied to the class-level, 2) which class will implement the validation, and 3) the error message to show.
package com.example.validatorsnippet.validator;
// imports
@Target({TYPE})
@Retention(RUNTIME)
@Constraint(validatedBy = CheckValuesValidator.class)
public @interface CheckValues {
String message() default "Maximum needs to be larger than the minimum value entered";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
Implementing the validator:
package com.example.validatorsnippet.validator;
// imports
public class CheckValuesValidator implements ConstraintValidator<CheckValues, Clazz> {
@Override
public boolean isValid(Clazz clazz, ConstraintValidatorContext constraintValidatorContext) {
return clazz.getMin() < clazz.getMax();
}
}
Adding the constraint to the class:
package com.example.validatorsnippet.domain;
// imports
@CheckValues
public class Clazz {
@Min(value =0)
private int min;
private int max;
// getters and setters
}
Testing/previewing the validator:
In Spring boot we can add a CommandLineRunner implementation to run custom code, so here is one such example which illustrates the use of the above validator.
package com.example.validatorsnippet.runners;
// imports
@Component
public class ValidationExample implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Clazz clazz = new Clazz();
clazz.setMin(5);
clazz.setMax(3);
Set<ConstraintViolation<Clazz>> constraintViolations = validator.validate(clazz);
System.out.println(constraintViolations.iterator().next().getMessage());
}
}