Есть ли способ получить переменную в пользовательский ConstraintValidator при использовании JAX-RS? - PullRequest
0 голосов
/ 03 июня 2019

При десериализации полезной нагрузки JSON я хочу проверить номер телефона с помощью пользовательского валидатора. Этот валидатор должен знать, в какой стране находится клиент, чтобы правильно проанализировать номер телефона. Страна, которую я могу найти в заголовке http Accept-Language.

Проблема в том, как я могу предоставить пользовательскому валидатору эти дополнительные метаданные?

Я был уверен, что @Context внедрит HttpHeaders в PhoneNumberValidator, но это не работает:

    @Context
    private HttpHeaders mHttpHeaders;

Поле равно нулю.

Конечная точка API:

@Path("customer")
public class CustomerResource {

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postCustomer(@Valid Customer pCustomer) {
        return Response.ok(pCustomer).build();
    }
}

POJO:

@Getter
@Setter
public class Customer {
    @NotNull
    private String firstName;

    @ValidPhoneNumber
    private String mobileNumber;
}

Интерфейс валидатора:

@Documented
@Retention(RUNTIME)
@Target({ TYPE, FIELD })
@Constraint(validatedBy = { PhoneNumberValidator.class })
public @interface ValidPhoneNumber {
    String message() default "Phone number is not valid!";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Пользовательский валидатор:

@Slf4j
public class PhoneNumberValidator implements ConstraintValidator<ValidPhoneNumber, String> {    
    @Override
    public boolean isValid(String vTelephone, ConstraintValidatorContext pContext) {
        final PhoneNumberUtil vPhoneNumberUtil = PhoneNumberUtil.getInstance();
        // TODO: Get the country in here somehow
        final String vCountry = "GB";      
        try {
            PhoneNumber vPhoneNumber = vPhoneNumberUtil.parse(vTelephone, vCountry);
            if (!vPhoneNumberUtil.isValidNumber(vPhoneNumber)) {
                log.error("Invalid {} phone number: {}", vCountry, vTelephone);
                return false;                
            }
        } catch (NumberParseException e) {
            log.error("Error parsing {} as a phone number in {}: {}", vTelephone, vCountry, e.getMessage());
            return false;
        }
        return true;
    }
}

1 Ответ

1 голос
/ 03 июня 2019

Объект HttpHeaders не является (пока) управляемым компонентом CDI - я говорю пока, потому что это является частью плана для JAX-RS 3.0 Jakarta быть компонентом CDI, но для JAX-RS 2.1 и более ранних версий он нет.

Но класс ресурсов может быть управляемым компонентом CDI. Таким образом, вы можете добавить HttpHeaders в класс CustomerResource, а затем предоставить метод получения, который будет обращаться к заголовкам. Затем используйте @Inject в вашем классе валидатора, чтобы внедрить ваш ресурс. Затем вы можете получить доступ к заголовкам из валидатора.

Примерно так:

@RequestScoped
public class PhoneNumberValidator implements ConstraintValidator<ValidPhoneNumber, String> {
    @Inject
    CustomerResource customerResource;

    @Override
    public boolean isValid(String vTelephone, ConstraintValidatorContext pContext) {
        // Get the country in here using the original resource instance
        final String vCountry = customerResource.getHeaderString("COUNTRY");
        try {
            validate(vTelephone, vCountry);
        } catch (Throwable t) {
            System.out.printf("Error parsing {0} as a phone number in {1}: {2}", vTelephone, vCountry, t.getMessage());
            return false;
        }
        return true;
    }
...

Обновление класса ресурса следующим образом:

@RequestScoped
@Path("customer")
public class CustomerResource {

    @Context
    private HttpHeaders headers;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postCustomer(@Valid Customer pCustomer) {
        return Response.ok(pCustomer).build();
    }

    String getHeaderString(String headerName) {
        return headers.getHeaderString(headerName);
    }
...

Я написал рабочий образец, который может помочь: https://github.com/andymc12/ContextVarInValidatorSample

Надеюсь, это поможет, Энди

...