本文介绍了如何在Jersey调用之前获取与URI匹配的资源方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现,用于对请求的参数进行自定义验证。我需要查找将与URI匹配的资源方法,以便我可以从方法的参数中删除自定义注释。



基于我应该可以注入然后使用它来匹配方法:

  public final class MyRequestFilter实现ContainerRequestFilter {

@Context private ExtendedUriInfo uriInfo;

@Override
public ContainerRequest filter(ContainerRequest containerRequest){

System.out.println(uriInfo.getMatchedMethod());

return containerRequest;
}
}

但显然会返回 null ,一直到实际调用该方法为止(此时对我来说进行验证已经太晚了)。 / p>

如何在调用资源方法之前检索将与给定URI匹配的方法? / p>




对于那些感兴趣的人,我正在尝试滚动我自己的必需参数验证,如。

解决方案

我想出了如何仅使用Jersey来解决我的问题。显然没有办法将请求的URI与调用该方法之前匹配的方法相匹配,至少在Jersey 1.x中是这样。但是,我能够使用为每个单独的资源方法创建 ResourceFilter - 这些过滤器可以通过这种方式了解目标方法提前。



这是我的解决方案,包括所需查询参数的验证(使用Guava和JSR 305):

  public final class ValidationFilterFactory实现ResourceFilterFactory {

@Override
public List< ResourceFilter> create(AbstractMethod abstractMethod){

//跟踪所需的查询参数名称
final ImmutableSet.Builder< String> requiredQueryParamsBuilder =
ImmutableSet.builder();

//从资源方法中获取参数列表
final ImmutableList< Parameter> params =
Invokable.from(abstractMethod.getMethod())。getParameters();

for(参数param:params){
//如果param未标记为@Nullable,
if(!param.isAnnotationPresent(Nullable.class)){
//尝试获取@QueryParam值
@Nullable final QueryParam queryParam =
param.getAnnotation(QueryParam.class);
//如果它存在,将其值添加到集合
if(queryParam!= null){
requiredQueryParamsBuilder.add(queryParam.value());
}
}
}

//返回此资源方法的新验证过滤器
return Collections。< ResourceFilter> singletonList(
新的ValidationFilter(requiredQueryParamsBuilder.build())
);
}

私有静态最终类ValidationFilter实现ResourceFilter {

final ImmutableSet< String> requiredQueryParams;

private ValidationFilter(ImmutableSet< String> requiredQueryParams){
this.requiredQueryParams = requiredQueryParams;
}

@Override
public ContainerRequestFilter getRequestFilter(){
return new ContainerRequestFilter(){
@Override
public ContainerRequest filter(ContainerRequest)请求){

final Collection< String> missingRequiredParams =
Sets.difference(
requiredQueryParams,
request.getQueryParameters()。keySet()
);

if(!missingRequiredParams.isEmpty()){

final String message =
缺少必需的查询参数:+
Joiner.on( ,)。join(missingRequiredParams);

final响应响应=响应
.status(Status.BAD_REQUEST)
.entity(message)
.build();

抛出新的WebApplicationException(响应);
}

返回请求;
}
};
}

@Override
public ContainerResponseFilter getResponseFilter(){
return null;
}
}
}

以及 ResourceFilterFactory 在Jersey注册为 web.xml 中的servlet的init参数:

 < init-param> 
< param-name> com.sun.jersey.spi.container.ResourceFilters< / param-name>
< param-value> my.package.name.ValidationFilterFactory< / param-value>
< / init-param>

启动时, ValidationFilterFactory.create 被调用对于泽西岛检测到的每种资源方法。



为了让我走上正轨,点击这篇文章:


I'm trying to implement a ContainerRequestFilter that does custom validation of a request's parameters. I need to look up the resource method that will be matched to the URI so that I can scrape custom annotations from the method's parameters.

Based on this answer I should be able to inject ExtendedUriInfo and then use it to match the method:

public final class MyRequestFilter implements ContainerRequestFilter {

    @Context private ExtendedUriInfo uriInfo;

    @Override
    public ContainerRequest filter(ContainerRequest containerRequest) {

        System.out.println(uriInfo.getMatchedMethod());

        return containerRequest;
    }
}

But getMatchedMethod apparently returns null, all the way up until the method is actually invoked (at which point it's too late for me to do validation).

How can I retrieve the Method that will be matched to a given URI, before the resource method is invoked?


For those interested, I'm trying to roll my own required parameter validation, as described in JERSEY-351.

解决方案

I figured out how to solve my problem using only Jersey. There's apparently no way to match a request's URI to the method that will be matched before that method is invoked, at least in Jersey 1.x. However, I was able to use a ResourceFilterFactory to create a ResourceFilter for each individual resource method - that way these filters can know about the destination method ahead of time.

Here's my solution, including the validation for required query params (uses Guava and JSR 305):

public final class ValidationFilterFactory implements ResourceFilterFactory {

    @Override
    public List<ResourceFilter> create(AbstractMethod abstractMethod) {

        //keep track of required query param names
        final ImmutableSet.Builder<String> requiredQueryParamsBuilder =
                ImmutableSet.builder();

        //get the list of params from the resource method
        final ImmutableList<Parameter> params =
                Invokable.from(abstractMethod.getMethod()).getParameters();

        for (Parameter param : params) {
            //if the param isn't marked as @Nullable,
            if (!param.isAnnotationPresent(Nullable.class)) {
                //try getting the @QueryParam value
                @Nullable final QueryParam queryParam =
                        param.getAnnotation(QueryParam.class);
                //if it's present, add its value to the set
                if (queryParam != null) {
                    requiredQueryParamsBuilder.add(queryParam.value());
                }
            }
        }

        //return the new validation filter for this resource method
        return Collections.<ResourceFilter>singletonList(
                new ValidationFilter(requiredQueryParamsBuilder.build())
        );
    }

    private static final class ValidationFilter implements ResourceFilter {

        final ImmutableSet<String> requiredQueryParams;

        private ValidationFilter(ImmutableSet<String> requiredQueryParams) {
            this.requiredQueryParams = requiredQueryParams;
        }

        @Override
        public ContainerRequestFilter getRequestFilter() {
            return new ContainerRequestFilter() {
                @Override
                public ContainerRequest filter(ContainerRequest request) {

                    final Collection<String> missingRequiredParams =
                            Sets.difference(
                                    requiredQueryParams,
                                    request.getQueryParameters().keySet()
                            );

                    if (!missingRequiredParams.isEmpty()) {

                        final String message =
                                "Required query params missing: " +
                                Joiner.on(", ").join(missingRequiredParams);

                        final Response response = Response
                                .status(Status.BAD_REQUEST)
                                .entity(message)
                                .build();

                        throw new WebApplicationException(response);
                    }

                    return request;
                }
            };
        }

        @Override
        public ContainerResponseFilter getResponseFilter() {
            return null;
        }
    }
}

And the ResourceFilterFactory is registered with Jersey as an init param of the servlet in web.xml:

<init-param>
    <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
    <param-value>my.package.name.ValidationFilterFactory</param-value>
</init-param>

At startup, ValidationFilterFactory.create gets called for each resource method detected by Jersey.

Credit goes to this post for getting me on the right track: How can I get resource annotations in a Jersey ContainerResponseFilter

这篇关于如何在Jersey调用之前获取与URI匹配的资源方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 11:09