我正在探索JAX-RS应用程序中MatrixURIs的使用。在此过程中,我注意到带注释的@MatrixParam参数似乎只能从最后一段中获取矩阵参数(这使得尝试使用sub-resource locators有点痛苦)。我想知道这是一个错误,还是规范的一部分(为什么?),或者仅仅是一个未定义的破解。

我知道我可能会想出一种使用@Context注入(inject)的UriInfo对象的方法(该对象的确会根据自己在定位器链中的位置而变化),但这很难看。

快速浏览JAX-RS 1.1 spec ...我能找到与之不兼容的最接近的内容是:§3.2



但这是关于构造函数/字段注入(inject)的问题,而不是第3.3.2节中的方法参数:



但是,当然,注释的语义看似模糊。

运行时环境详细信息:

  • 新泽西州1.13,1.15
  • Tomcat 7.0.29
  • Java 1.6.0_31(Apple)
  • MacOS X 10.7.5

  • 资源示例:
    public class Zero {
    
        public static final String[] IDS = { "1", "2", "3" };
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Map<String, Object> getMe(@Context final UriInfo info) {
            final UriBuilder builder = info.getAbsolutePathBuilder().path("one");
            final UriBuilder two = builder.clone().matrixParam("id", "{one}", "{two}");
    
            final List<String> links = new ArrayList<String>();
            for (int i = 0; i < IDS.length; i++) {
                final String first = IDS[i];
                for (int j = i + 1; j < IDS.length; j++) {
                    final String second = IDS[j];
                    links.add(two.build(first, second).toASCIIString());
                }
            }
    
            final Map<String, Object> toReturn = new HashMap<String, Object>();
            toReturn.put("class", getClass().getSimpleName());
            toReturn.put("next", builder.build().toASCIIString());
            toReturn.put("skip", links);
    
            return toReturn;
        }
    
        /*************************/
        /**** <PROBLEM CHILD> ****/
        /*************************/
        @Path("one")
        public Object getNext(@MatrixParam("id") final Set<String> ids) {
            if (ids.isEmpty()) {
                return new One();
            }
            return new Two(ids.toArray(new String[ids.size()]));
        }
        /*************************/
        /**** </PROBLEM CHILD> ***/
        /*************************/
    
        public static class One {
            @GET
            @Produces(MediaType.APPLICATION_JSON)
            public Map<String, Object> getMe(@Context final UriInfo info) {
                final UriBuilder builder = info.getAbsolutePathBuilder().path("{id}");
                final List<String> links = new ArrayList<String>();
                for (final String id : IDS) {
                    links.add(builder.build(id).toASCIIString());
                }
                final Map<String, Object> toReturn = new HashMap<String, Object>();
                toReturn.put("class", getClass().getSimpleName());
                toReturn.put("next", links);
                toReturn.put("last", getLastURI(info));
                return toReturn;
            }
    
            @Path("{id}")
            public Two getNext(@PathParam("id") final String id) {
                return new Two(id);
            }
        }
    
        public static class Two {
    
            private final String[] myids;
            private final Three three;
    
            public Two(final String... ids) {
                three = new Three(ids);
                myids = ids;
            }
    
            @GET
            @Produces(MediaType.APPLICATION_JSON)
            public Map<String, Object> getMe(@Context final UriInfo info) {
                final UriBuilder builder = info.getAbsolutePathBuilder().path("three");
                final Map<String, Object> toReturn = new HashMap<String, Object>();
                toReturn.put("class", getClass().getSimpleName());
                toReturn.put("ids", myids);
                toReturn.put("next", builder.build().toASCIIString());
                toReturn.put("last", getLastURI(info));
                return toReturn;
            }
    
            @Path("three")
            public Three getNext() {
                return three;
            }
        }
    
        public static class Three {
            private final String[] myids;
    
            public Three(final String... ids) {
                myids = ids;
            }
    
            @GET
            @Produces(MediaType.APPLICATION_JSON)
            public Map<String, Object> getMe(@Context final UriInfo info) {
                final Map<String, Object> toReturn = new HashMap<String, Object>();
                toReturn.put("class", getClass().getSimpleName());
                toReturn.put("ids", myids);
                toReturn.put("last", getLastURI(info));
                return toReturn;
            }
        }
    
        /**
         * Helper method since info.getMatchedURIs doesn't play nice with Matrix Params
         * @param info info object
         * @return parent URI
         */
        public static final String getLastURI(final UriInfo info) {
            final List<PathSegment> segments = info.getPathSegments(false);
            final UriBuilder builder = info.getBaseUriBuilder();
            for (int i = 0; i < segments.size() - 1; i++) {
                final PathSegment segment = segments.get(i);
                builder.path(segment.getPath());
                final MultivaluedMap<String, String> matrixParams = segment.getMatrixParameters();
                if (!matrixParams.isEmpty()) {
                    for (final Map.Entry<String, List<String>> param : matrixParams.entrySet()) {
                        final String name = param.getKey();
                        final String[] values = param.getValue().toArray(new String[param.getValue().size()]);
                        builder.matrixParam(name, values);
                    }
                }
            }
            return builder.build().toASCIIString();
        }
    }
    

    上面的示例输出:
    http://localhost:8080/context/zero/one/2
    {
    "last":"http://localhost:8080/context/zero/one",
    "ids":["2"],
    "next":"http://localhost:8080/context/zero/one/2/three",
    "class":"Two"
    }
    
    http://localhost:8080/context/zero/one/2/three
    {
    "last":"http://localhost:8080/context/zero/one/2",
    "ids":["2"],
    "class":"Three"
    }
    
    http://localhost:8080/context/zero/one;id=1;id=2
    {
    "last":"http://localhost:8080/context/zero",
    "ids":["2","1"],
    "next":"http://localhost:8080/context/zero/one;id=1;id=2/three",
    "class":"Two"
    }
    
    http://localhost:8080/context/zero/one;id=1;id=2/three
    {
    "last": "http://localhost:8080/context/zero/one;id=1;id=2",
    "ids": ["three"],
    "next": "http://localhost:8080/context/zero/one;id=1;id=2/three/three",
    "class": "Two"
    }
    

    最佳答案

    我不能肯定地说,但我怀疑这是设计使然。假设您有一个这样的两层URI:

    /foo/bar
    

    在这两个级别上,都可以有一个名为filter的矩阵参数。您最终可能会获得如下所示的URL:
    /foo;filter=13/bar;filter=April
    

    在该路径的Jersey资源中,您将有一个用@MatrixParam(“filter”)注释的参数。 Jersey应该填写哪个过滤器参数?如果没有提供一个或另一个,该怎么办?

    刚刚实现了一些矩阵参数之后,我可以在当前实现中看到该值。指定@MatrixParam仅拉出最后一个级别。如果要在URI中更早使用矩阵参数,请指定@PathParameter并将参数类型设置为PathSegment。您可以从路径段中提取矩阵参数。

    通常,资源类将具有全局@Path,并且每个方法都将具有自己的@Path,添加到类级别设置中。在这种情况下,@MatrixParameter仅应用于最后的路径段似乎更有意义。

    因此,将所有这些放在一起(对于上面的示例)将产生以下结果
    @Path("{fooPath: foo}")
    public class FooResource {
    
    @GET
    @Path("bar")
    public String getFooBar(@PathParam("fooPath") PathSegment fooPath,
        @MatrixParam("filter") String filter) {
        MultivaluedMap<String, String> mParms = fooPath.getMatrixParameters();
        List<String> parms = mParms.get("filter");
        String fooFilter = parms.get(0);
        // ... the rest of your code
        }
    }
    

    09-27 06:44