When I enable the @Validated spring annotation at class level in a Rest controller, 2 validation contexts are generated (each one with a different prefix). The @Validated annotation is required as I want to use 2 different validation groups but as there are 2 validations context all validations are executed twice. I think all validations should be verified only once so:
@RestController
@RequestMapping
@Validated
public class KidController {
private final KidService kidService;
public KidController(KidService kidService) {
this.kidService = kidService;
}
@PostMapping
@Validated(OnRegistrationRequest.class)
@ResponseStatus(HttpStatus.CREATED)
public KidDTO createKidRegistration(@RequestBody @Valid KidDTO kid) {
return kidService.saveKid(kid);
}
}
public interface KidValidatorGroup {
interface OnRegistrationRequest extends Default {
}
interface OnCheckInPersist extends Default {
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({"id"})
@JsonInclude(Include.NON_NULL)
public class KidDTO {
@NotEmpty
private String id;
@NotEmpty
private String firstName;
@KidAgeConstraint
private Integer age;
@NotEmpty(groups = OnCheckInPersist.class)
private String roomDocId;
@Valid
private Set<AnswerDTO> answers;
@Valid
private Set<GuardianDTO> guardians;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldStrictDependentConstraint(principalField = "answer",
dependentField = "description")
@JsonInclude(Include.NON_NULL)
public class AnswerDTO {
@QuestionIdConstraint(groups = OnRegistrationRequest.class)
private String questionId;
}
I found the 2 contexts when debugging the application and the second one looks with method name like prefix.
In your code you have an annotation that triggers validation both on method parameter and on method return value:
@PostMapping
@Validated(OnRegistrationRequest.class) // this one is "@Valid" with a specified group and will be used for return value validation
@ResponseStatus(HttpStatus.CREATED)
public KidDTO createKidRegistration(@RequestBody @Valid /* this one is for method parameter */ KidDTO kid) {
return kidService.saveKid(kid);
}
See the different paths that you have in your screenshots. One is createKidRegistration.kid.firstName
that's the one for parameter. If you only need to validate the passed parameter with s specific group you should try to replace your @Valid
with @Validated(OnRegistrationRequest.class)
, and remove the @Validated
from the method level completely.