Validate only annotated parameters in javax.validation.ConstraintValidator

59 views Asked by At

I have a ConstraintValidator that needs to validate the input parameter (periodDays) depending on another parameter (id). To do this, I implemented validation logic based on ElementType.METHOD. My interface:

@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = { DaysPeriodValidator.class })
public @interface ValidDaysPeriod {
    // ...

and Validator:

@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class DaysPeriodValidator implements ConstraintValidator<ValidDaysPeriod, Object[]> {

    @Override
    public boolean isValid(Object[] objects, ConstraintValidatorContext context) {
        Integer testValue;
        String id;
        try {
            testValue = (Integer) objects[1];
            id = validateTenantId((String) objects[0]);
        } catch (Exception e) {
            return false;
        }
       // ... validation logic
        return valid;
    }
}

It works well for controller methods like

    @ValidDaysPeriod
    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public MyData getMyData(@Nullable String id,
                            @NotNull Integer periodDays) {

where parameters order is expected. But I'm not immune if somebody would write a new endpoint where parameters are not in this order. The Validator gets them in nameless Object[] objects, and if there are more Integer or String parameters, I can't recognize id and periodDays among them.

Is there a way to detect these parameters inside the Validator? For example:

  • add specific annotations to them
  • pass parameter names with values to the Object[] objects?
1

There are 1 answers

0
gad_gadskiy On BEST ANSWER

Eventually, I found an ability to get parameter names from the context. Their order is strictly the same as for values in Objects[].

public boolean isValid(Object[] objects, ConstraintValidatorContext context) {
        Integer testValue;
        String id;

        try {
            List<String> methodParameterNames = ((CrossParameterConstraintValidatorContextImpl) context).getMethodParameterNames();
            int idIdndex = methodParameterNames.indexOf(idParameterName);
            int periodDaysIndex = methodParameterNames.indexOf(periodDaysParameterName);
            testValue = (Integer) objects[periodDaysIndex];
            id = validateTenantId((String) objects[idIndex]);
        } catch (Exception e) {
            return false;
        }
        // validator logic
}

P.S. Guy who dislikes w/o comments, you can f*ck yourself:)