Jakarta ee 我可以用ApacheWink(JAX/RS)实现Hibernate(JSR303)方法验证吗

Jakarta ee 我可以用ApacheWink(JAX/RS)实现Hibernate(JSR303)方法验证吗,jakarta-ee,jax-rs,bean-validation,hibernate-validator,apache-wink,Jakarta Ee,Jax Rs,Bean Validation,Hibernate Validator,Apache Wink,我目前正在研究使用hibernate验证器支持使用JSR303注释进行方法验证。最初尝试使用代理(使用cglib生成)包装资源以执行验证,但是,这似乎已经走到了死胡同,因为我尝试的代理方法似乎没有复制参数注释,因此依赖于此的资源方法最终被调用时没有参数。我现在还有一个问题要问: 有没有一种替代机制可以挂接到wink的请求链中,从而在不使用代理的情况下执行类似的操作?您可以通过创建一个,并重写实际的来返回包含请求处理程序的列表,这是一种部分受支持的方法。本文将讨论此功能的配置。该请求处理程序将直

我目前正在研究使用hibernate验证器支持使用JSR303注释进行方法验证。最初尝试使用代理(使用cglib生成)包装资源以执行验证,但是,这似乎已经走到了死胡同,因为我尝试的代理方法似乎没有复制参数注释,因此依赖于此的资源方法最终被调用时没有参数。我现在还有一个问题要问:


有没有一种替代机制可以挂接到wink的请求链中,从而在不使用代理的情况下执行类似的操作?

您可以通过创建一个,并重写实际的来返回包含请求处理程序的列表,这是一种部分受支持的方法。本文将讨论此功能的配置。该请求处理程序将直接插入到请求处理链中,位于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 
    }
//从hibernate获取方法验证程序
MethodValidator validator=Validation.byProvider(HibernateValidator.class).configure()
.buildValidatorFactory().getValidator().unwrap(
MethodValidator.class);
//从JAX/RS内部提取方法参数、对象实例和方法元数据。
方法javaMethod=null;
对象实例=null;
Object[]参数=null;
SearchResult SearchResult=context.getAttribute(SearchResult.class);
javaMethod=searchResult.getMethod().getMetadata()
.getReflectionMethod();
parameters=searchResult.getInvocationParameters();
instance=searchResult.getResource().getInstance(上下文);
//使用所有这些来执行验证。。。
设置冲突=验证程序
.validateAllParameters(实例、javaMethod、参数);
如果(!inflictions.isEmpty()){
//对这里的违规行为做点什么
}

这有点骇人听闻,因为它依赖于wink的实现细节(据我所知是未文档化的)来获取实例、参数和元数据(如果它们提供了获取此信息的公共方式,那就太好了)。但是,使用代理有点可取,因为您不会从代理发生的反射中推断出多个开销。

我通过添加EJB拦截器成功地使用wink执行了bean验证。在这里,我使用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();
    }
}
@拦截器
公共类验证接收器{
Validator Validator=Validation.byProvider(ApacheValidationProvider.class).configure().buildValidatorFactory().getValidator();
@阿隆登沃克
公共对象验证(InvocationContext ctx)引发异常{
Object[]parameters=ctx.getParameters();
Set validateResult=new HashSet();
用于(对象参数:参数){
设置validateParam=validator.validate(参数);
validateResult.addAll(validateParam);
}
如果(!validateResult.isEmpty()){
抛出新的RestValidationException(validateResult);
}
返回ctx.procedure();
}
}
要输出的自定义异常:

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();  
    }  
}  
公共类RestValidationException扩展WebApplicationException{
List validationErrors=new ArrayList();
公共RestValidationException(集合>冲突){
对于(ConstraintViolation ConstraintViolation:违规){
字符串错误=constraintViolation.getPropertyPath().toString()+“:”+constraintViolation.getMessage();
validationErrors.add(错误);
}  
}  
@凌驾
公共响应getResponse(){
返回Response.status(status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_type).entity(validationErrors.build();
}  
}  
现在,您必须使用@Interceptors(ValidationInterceptor.class)注释REST资源,并且在进入该方法之前验证所有参数。 如果您没有使用EJB,那么可以使用cglib的MethodInterceptor拦截它(Spring可以在这里提供帮助)