Issue
I need to validate a payload for my spring boot api. I created a custom validated annotation for a list of key-value pairs (specialAccommodations) which is dependent on another beans value (dressingRoom). specialAccommodations is stored as a List< Map<String, String> > in the venue bean. The validation requirements are different per dressing room and set accordingly. The validtor works and I'm able to confirm by debugging that it's returning the correct boolean in the isValid method. However, the message is always blank. Any ideas? Is it bad practice to put the custom validation annotation on the bean?
Payload
{
"artist": {
"name": "",
"birthdate": "",
"dressingRoom": ""
},
"venue": {
"state": ""
"specialAccommodations": [
{
"water": "sparkling",
"snack": "chips",
...
}
]
}
}
Bean - maps the payload
@PayloadConstaints(message = "Error validating special accommodations")
public class payloadBean{
@Valid
private artistBean;
@Valid
private venueBean;
}
Validator Annotation
@Constraint(validatedBy = PayloadValidator.class)
@Target({TYPE, FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
public @iterface PayloadConstaints{
String message() default "{}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
I am unable to use the annotation in the controller and need access to the artist and venue beans to validate properly. The class that handles the validation logic implements ConstraintValidator<PayloadConstraint, payloadBean>.
I followed this example and it worked: https://blog.tericcabrel.com/write-custom-validator-for-body-request-in-spring-boot/#:~:text=Create%20custom%20validator,used%20on%20the%20input%20value.
However, they are validating a value from the bean, not the bean itself.
Solution
The default message should be updated. You must add to the list of validation errors in the validator class. The property node is the bean and the bean property you want to associate the error message with. Here are the following code changes I made:
Validator Annotation
String message() default "There is an error with the given payload.";
PayloadValidator Class
@Override
public boolean isValid(PayloadBean bean, ConstraintValidatorContext context){
boolean isValid;
// logic here
// assume the artistBean has a String name
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode("artistBean.name").addConstraintViolation();
return isValid;
}
Answered By - milo
Answer Checked By - Willingham (JavaFixing Volunteer)