Lets say I have an Object with two fields which should be validated:
public class AnyRQ {
@MerchantAccountValidation
@JsonProperty(value = "merchant-account")
private MerchantAccount merchantAccount;
@RequestIdValidation
@JsonProperty(value = "request-id")
private String requestId;
}
Both of the Annotations @MerchantAccountValidation
and @RequestIdValidation
implements a ConstraintValidator
and including the rules to be valid or not. (Just show one class)
public class RequestIdValidator
implements ConstraintValidator<RequestIdValidation, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.length() > 10;
}
}
Now I have a Controller with two endpoints. Endpoint 1 should validate both Fields but Request 2 should just validate requestId
.
@RestController
@RequestMapping("/validate")
public class ValidController {
@PostMapping("/endpoint1")
public ResponseEntity<?> register(@Valid @RequestBody AnyRQ req, Errors errors) {
if (errors.hasErrors()) {
}
return null;
}
@PostMapping("/endpoint2")
public ResponseEntity<?> authorization(@Valid @RequestBody AnyRQ req, Errors errors) {
if (errors.hasErrors()) {
}
return null;
}
}
Is there any way to achive a kind of priority or inheritance to get this working? I was thinking about to have the Validation Annotation on the method level of the endpoints. But unfortunately this is not working.
Patrick!
To achieve the desired outcome you can use @GroupSequence. It mostly meant for ordering validations (no need to check that entity exists in database, if id is null f.e.), but would work for your task. Let's say you have 2 validation groups (better names are required :) ):
public interface InitialValidation {
}
@GroupSequence(InitialValidation.class)
public interface InitialValidationGroup {
}
public interface FullValidation {
}
@GroupSequence(FullValidation.class)
public interface FullValidationGroup {
}
Specify them in the DTO:
public class AnyRQ {
@MerchantAccountValidation(groups = FullValidation.class)
@JsonProperty(value = "merchant-account")
private MerchantAccount merchantAccount;
@RequestIdValidation(groups = {InitialValidation.class, FullValidation.class})
@JsonProperty(value = "request-id")
private String requestId;
}
And in the controller use @Validated instead of @Valid to provide corresponding group:
@RestController
@RequestMapping("/validate") public class ValidController {
@PostMapping("/endpoint1")
public ResponseEntity<?> register(@Validated(FullValidationGroup.class) @RequestBody AnyRQ req, Errors errors) {
if (errors.hasErrors()) {
}
return null;
}
@PostMapping("/endpoint2")
public ResponseEntity<?> authorization(@Validated(InitialValidationGroup.class) @RequestBody AnyRQ req, Errors errors) {
if (errors.hasErrors()) {
}
return null;
}
}
The other option is to keep one group in DTO, but specify two groups in controller for @Validated.