I am using validation-api-2.0.1.Final
and hibernate-validator-6.0.13.Final
. I would like to do validation for the below case,
I have created a custom validation to validate List<Map<String,Object>>
BookInfo.java
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {BookInfoValidator.class}
)
public @interface BookInfo {
String message() default "Should not be empty";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
BookInfoValidator.java
public class BookInfoValidator implements ConstraintValidator<ValidateUserInfo, List<Map<String, Object>>> {
private final ContentRepositoryClient contentRepository;
public ValidateUserInfoValidator(ContentRepositoryClient contentRepository) {
this.contentRepository = contentRepository;
}
@Override
public void initialize(ValidateUserInfo constraintAnnotation) {
}
@Override
public boolean isValid(List<Map<String,Object>> map, ConstraintValidatorContext constraintValidatorContext) {
//In the list of Map the key will be "text,email,date etc etc" based on the key i would like to
//validate with the proper validation constraints
//ex) for Email invoke javax.validation.constraints.Email.class from validation-api
//I am not sure how to manually invoke the validation annotations.
return false;
}
}
BookInfoView.java
class BookInfoView {
@BookInfo
private List<Map<String, Object>> bookInfos;
}
In the list of Map the key will be "text, email, date etc". Based on the key I would like to validate with the proper validation constraints
exception for Email invoke javax.validation.constraints.Email.class
from validation-api. I am not sure how to manually invoke the validation annotations.
Any hint or help will be much appreciated.
I am not sure how to manually invoke the validation annotations.
I am answering above quoted lines. Yes, it is possible to invoke validation programmatically and in case of validation failures you will receive all failure messages in a set. Below are the steps to do the same:
ValidatorFactory
Validator
instance from ValidatorFactory
validate()
methodconstraintViolations.iterator().next().getMessage()
Show some code, below is the code snippet for all four steps mentioned above:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<BookInfoView>> constraintViolations = validator.validate(bookInfoViewObj);
assertEquals( "Should not be empty", constraintViolations.iterator().next().getMessage() );
Hibernate Validator framework provides various other capabilities to validate one or more entities and then process the result. Better you have look at official document.
There's no 'nice' way of accessing validator implementations for constraints (email , not null etc.). While you could create instances of those validators and store them in your BookInfoValidator
you would need to do a lot of additional work. As for each validator its ConstraintValidator#initialize()
method. While in case of simple constraints like @NotNull
there's actually noting to initialize, the same check can easily be performed without this validator. And in case of a more complex ones like @Email
you would need to create your own proxy class for the annotation so you could properly initialize the constraint validator.
With that said I would suggest to write a wrapper class for your Map
, something like:
public class BookInfoWrapper {
private final Map<String, Object> data;
public BookInfoWrapper(Map<String, Object> data) {
this.data = data;
}
@NotNull
public Map<String, Object> getUser(){
return (Map<String, Object>) data.get( "user" );
}
@Email
public String getEmail(){
return Objects.toString(( getUser() ).get( "email" ));
}
// and any other constraints you need
}
And then convert your list of maps to these wrappers before validation.
I can also see that you have a repository in your validator, hence I think that you might want to derive rules "dynamically". In such case you might want to check out the programmatic API provided by Hibernate Validator. Using it you should be able to build the rules you need based on the data retrieved from the database. But still you would need to wrap the maps first.
To summarize it all, sadly there's no nice and easy solution for your particular case yet. We are working on a validation of free form objects but it'll take us some time to be able to release it. Hence I would suggest that you should either
BookInfoValidator
without using built-in constraints. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With