I am trying to validate two custom query path variables in this custom query:
@Slf4j
@AllArgsConstructor
@RestController
@Validated
@RequestMapping("api/standing_orders")
public class StandingOrderController {
...
@GetMapping("/by_validity_date_from_to")
public ResponseEntity<List<StandingOrderResponseDTO>> getByValidFromBetween(
@StartDateBeforeEndDate @RequestParam LocalDate startDate, @StartDateBeforeEndDate @RequestParam LocalDate endDate) {
log.info("Received request to find standing order valid from {} to {}", startDate, endDate);
List<StandingOrderResponseDTO> orders = standingOrderService.findByValidFromBetween(startDate, endDate);
log.info(orders.toString());
return ResponseEntity.ok(orders);
}
This custom query is for showing the standing orders between two dates. I want to make sure that the starting date is not later than the ending date, so I am making a ConstraintValidator for it:
package sk.softec.akademia.demo.validation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = StartDateBeforeEndDateValidator.class)
public @interface StartDateBeforeEndDate {
String message() default "Start date cannot be later than end date";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
and
package sk.softec.akademia.demo.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import sk.softec.akademia.demo.DTO.StandingOrderRequestDTO;
import java.time.LocalDate;
public class StartDateBeforeEndDateValidator implements ConstraintValidator<StartDateBeforeEndDate, Object[]> {
@Override
public void initialize(StartDateBeforeEndDate value) {}
@Override
public boolean isValid(Object[] values, ConstraintValidatorContext context) {
if (values == null || values.length < 2 || !(values[0] instanceof LocalDate) || !(values[1] instanceof LocalDate)) {
return true;
}
LocalDate startDate = (LocalDate) values[0];
LocalDate endDate = (LocalDate) values[1];
return startDate == null || endDate == null || !startDate.isAfter(endDate);
}
Unfortunately, it doesn't work as intented, because I get this: No validator could be found for constraint ...demo.validation.StartDateBeforeEndDate' validating type 'java.time.LocalDate'. Check configuration for 'getByValidFromBetween.startDate'
I don't want to make a new DTO for it, so my question is, is it actually possible to validate two request parameters together?
Any help would be much appreciated.
Haven't tried it, but you can try to pass additional to your parameters list Spring WebRequest as described here
Than apply StartDateBeforeEndDateValidator
on WebRequest. With
WebRequest.getParameter
you will have access to passed parameters as String
public class StartDateBeforeEndDateValidator implements ConstraintValidator<StartDateBeforeEndDate, WebRequest> {
@Override
public void initialize(StartDateBeforeEndDate value) {}
@Override
public boolean isValid(WebRequest request, ConstraintValidatorContext context) {
LocalDate startDate = LocalDate.parse(request.getParameter("startDate");
LocalDate endDate = LocalDate.parse(request.getParameter("endDate"); //null check. parse check to be added
return startDate == null || endDate == null || !startDate.isAfter(endDate);
}
controller
@GetMapping("/by_validity_date_from_to")
public ResponseEntity<List<StandingOrderResponseDTO>> getByValidFromBetween(
@RequestParam LocalDate startDate, @RequestParam LocalDate endDate, @StartDateBeforeEndDate WebRequest request ) {
log.info("Received request to find standing order valid from {} to {}", startDate, endDate);
List<StandingOrderResponseDTO> orders = standingOrderService.findByValidFromBetween(startDate, endDate);
log.info(orders.toString());
return ResponseEntity.ok(orders);
}