如何在 Jersey 调用 URI 之前将资源方法与 URI 匹配?

2022-09-02 01:01:09

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

基于这个答案,我应该能够注入ExtendedUriInfo,然后使用它来匹配该方法:

public final class MyRequestFilter implements ContainerRequestFilter {

    @Context private ExtendedUriInfo uriInfo;

    @Override
    public ContainerRequest filter(ContainerRequest containerRequest) {

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

        return containerRequest;
    }
}

但是getMatchedMethod显然会返回,一直到实际调用该方法(此时我进行验证为时已晚)。null

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


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


答案 1

实际上,您应该尝试注入到自定义请求筛选器中。我已经用RESTEasy尝试过它,它在那里工作。优点是您可以针对 JSR 接口而不是 Jersey 实现进行编码。ResourceInfo

public class MyFilter implements ContainerRequestFilter
{
    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext)
            throws IOException
    {
        Method theMethod = resourceInfo.getResourceMethod();
        return;
    }
}

答案 2

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

这是我的解决方案,包括对所需查询参数的验证(使用Guava和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;
        }
    }
}

并且 已在泽西岛注册为 servlet 的初始化参数:ResourceFilterFactoryweb.xml

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

在启动时,为 Jersey 检测到的每个资源方法调用。ValidationFilterFactory.create

感谢这篇文章让我走上了正确的轨道:我如何在泽西岛容器ResponseFilter中获取资源注释


推荐