Могу ли я реализовать валидацию метода Hibernate (JSR 303) с помощью Apache wink (JAX / RS) - PullRequest
3 голосов
/ 05 августа 2011

В настоящее время я изучаю использование поддержки валидаторов hibernate для валидации метода с использованием аннотаций JSR 303.Первоначальная попытка попыталась обернуть ресурсы прокси-сервером (сгенерированным с помощью cglib), который выполнил проверку, однако, это, похоже, зашло в тупик, так как прокси-методы, которые я пробовал, не копируют аннотации параметров,Методы ресурсов, которые полагаются на это, в конечном итоге вызываются без параметров.У меня есть еще один открытый вопрос по этому пункту:

Как я могу создать динамический прокси в java, который сохраняет аннотации параметров для методов?

Есть ли альтернативамеханизм для подключения к цепочке запросов подмигивания, чтобы сделать что-то подобное без использования прокси?

Ответы [ 2 ]

4 голосов
/ 09 августа 2011

Вы можете сделать это частично поддерживаемым способом, создав RequestHandler и переопределив фактическую HandlersFactory , чтобы вернуть список, содержащий ваш обработчик запросов.Конфигурация для этого обсуждается здесь .Этот обработчик запроса будет вставлен в цепочку обработки запроса непосредственно перед InvokeMethodHandler (который является последним вызванным обработчиком запроса, и именно он фактически вызывает метод ресурса).

На основе чтения исходного кода для InvokeMethodHandler (который фактически вызывает ваш ресурс JAX / RS), вы можете получить параметры, параметры экземпляра и метода следующим образом:

   // Get Method Validator from hibernate 
   MethodValidator validator = Validation.byProvider(HibernateValidator.class).configure()
            .buildValidatorFactory().getValidator().unwrap(
                    MethodValidator.class);

    // Extract the method parameters, object instance and method metadata from the JAX/RS internals.
    Method javaMethod = null;
    Object instance = null;
    Object[] parameters = null;
    SearchResult searchResult = context.getAttribute(SearchResult.class);

    javaMethod = searchResult.getMethod().getMetadata()
            .getReflectionMethod();

    parameters = searchResult.getInvocationParameters();
    instance = searchResult.getResource().getInstance(context);

    // Use all this to perform validation...
    Set<MethodConstraintViolation<Object>> violations = validator
            .validateAllParameters(instance, javaMethod, parameters);
    if (!violations.isEmpty()) {
         // do something with the violations here 
    }

Это несколько странно, так как полагается на(насколько я могу судить недокументировано) детали реализации wink для получения экземпляра, параметров и метаданных (было бы неплохо, если бы они предоставили публичный способ получить эту информацию).Тем не менее, это несколько предпочтительнее, чем использование прокси, потому что вы не выводите несколько накладных расходов от отражения, которые происходят с прокси.

2 голосов
/ 04 марта 2014

Мне удалось выполнить проверку бина с помощью Wink, добавив EJB Interceptor.Здесь я использовал валидатор Openjpa в качестве провайдера:

@Interceptor
public class ValidationInterceptor {

    Validator validator = Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory().getValidator();

    @AroundInvoke
    public Object validate(InvocationContext ctx) throws Exception {
        Object[] parameters = ctx.getParameters();
        Set<ConstraintViolation<Object>> validateResult = new HashSet<>();

        for (Object parameter : parameters) {
            Set<ConstraintViolation<Object>> validateParam = validator.validate(parameter);
            validateResult.addAll(validateParam);
        }
        if (!validateResult.isEmpty()) {
            throw new RestValidationException(validateResult);
        }
        return ctx.proceed();
    }
}

Настраиваемое исключение, чтобы быть симпатичным выводом:

public class RestValidationException extends WebApplicationException {  

    List<String> validationErrors = new ArrayList<String>();  

    public RestValidationException(Set<? extends ConstraintViolation<?>> violations) {  
        for(ConstraintViolation<?> constraintViolation : violations) {  
            String error = constraintViolation.getPropertyPath().toString() + ": " + constraintViolation.getMessage();  
            validationErrors.add(error);  
        }  
    }  

    @Override  
    public Response getResponse() {  
        return Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(validationErrors).build();  
    }  
}  

Теперь вам нужно аннотировать ресурсы REST с помощью @Interceptors (ValidationInterceptor.class)и все параметры проверяются перед вводом метода.Если вы не используете EJB, вы можете перехватить его с помощью MethodInterceptor cglib (здесь может помочь Spring).

...