JAX-RS如何匹配两个或多个兼容的@Path表达式? [英] How JAX-RS matches for two or more compatible @Path expressions?

查看:75
本文介绍了JAX-RS如何匹配两个或多个兼容的@Path表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过以下两种方法,

@GET
@Path("/{id: \\d+}")
public MyEntity readSingleById(@PathParam("id") long id) {
}


@GET
@Path("/{name: .+}")
public MyEntity readSingleByName(@PathParam("name") String name) {
}

以下请求是否有可能与readSingleByName匹配而不与readSingleById匹配?

Is there any chance that following request matches to readSingleByName not to readSingleById?

GET /1234 HTTP/1.1

如果是,该怎么办?指定的一般规则是什么?

If so, what can I do? What is the general rule specified?

对不起,如果有人这么说,我应该检查一下规格.

Sorry I should've checked the spec if anyone say so.

推荐答案

以下请求是否有可能与readSingleByName匹配而不与readSingleById匹配?"

"Is there any chance that following request matches to readSingleByName not to readSingleById?"

让我们对其进行测试:

@Path("/ambiguous")
public class AmbiguousResource {

    @GET
    @Path("/{id: \\d+}")
    public Response readSingleById(@PathParam("id") long id) {
        return Response.ok("callById").build();
    }

    @GET
    @Path("/{name: .+}")
    public Response readSingleByName(@PathParam("name") String name) {
        return Response.ok("callByName").build();
    }
}

@Test
public void testGetIt() throws Exception {
    int idCount = 0;
    int nameCount = 0;
    for (int i = 0; i < 10 * 1000; i++) {
        String response = c.target(Main.BASE_URI)
            .path("ambiguous").path("1234").request().get(String.class);
        switch (response) {
            case "callById":
                idCount++;
                break;
            case "callByName":
                nameCount++;
                break;
        }
    }
    System.out.println("Id Count: " + idCount);
    System.out.println("Name Count: " + nameCount);  
}

结果:

泽西2.13
ID数:10000
姓名数:0

Jersey 2.13
Id Count: 10000
Name Count: 0

Resteasy 3.0.7
ID数:10000
名称计数:0

Resteasy 3.0.7
Id Count: 10000
Name Count: 0

现在让我们玩一下.如果我们切换方法声明位置,即"id方法"之前的"name方法",会发生什么情况

Now let's do play with it a bit. What happens if we switch the method declaration positions, i.e. the "name method" before the "id method"

@GET
@Path("/{name: .+}")
public Response readSingleByName(@PathParam("name") String name) {
    return Response.ok("callByName").build();
}

@GET
@Path("/{id: \\d+}")
public Response readSingleById(@PathParam("id") long id) {
    return Response.ok("callById").build();
}

现在,如果我们运行相同的测试,则Jersey结果将相同(id == 10000,名称== 0).但是有了Resteasy,我们得到了

Now if we run the same test, the Jersey result will be the same (id == 10000, name == 0). But with with Resteasy, we get

Resteasy 3.0.7
ID计数:0
姓名数:10000

Resteasy 3.0.7
Id Count: 0
Name Count: 10000

因此,这种歧义程度的行为似乎是特定于实现的.摘自JAX-RS规范的摘录(此时为方法过滤"):

So it appears the behavior at this level of ambiguity is implementation specific. A snippet from the JAX-RS spec states (at this point of "method filtering"):

使用每个成员中文字字符的数量作为主键(降序),捕获组的数量作为辅助键(降序)以及具有非默认正则表达式的捕获组数,对E进行排序(即不是([^ /]+?))作为三级键(降序)

Sort E using the number of literal characters in each member as the primary key (descending order), the number of capturing groups as a secondary key (descending order) and the number of capturing groups with non-default regular expressions (i.e. not ([^ /]+?)) as the tertiary key (descending order)

这基本上是这样的:

  1. 检查文字字符的数量. (对于您而言,没有).
  2. 检查{ }的数量(是否使用正则表达式)
  3. 检查{ }的数量(非正则表达式)
  1. Check the number of literal characters. (In your case, none).
  2. Check the number of { }s (regex or not)
  3. Check the number of { }s (non regex)

应从此处检查正则表达式.但是,它没有任何地方声明应检查所有剩余的候选方法的最佳匹配"正则表达式,这是您希望的情况.

From there the regex should be checked. But it does not anywhere state that all remaining candidate methods should be checked for "best matching" regex, which is the case you are hoping for.

我对正则表达式不太满意,因此确定最佳匹配"正则表达式的概念困扰我.我可能是错的,但看来这是泽西岛正在做的事情.我还测试了将id参数设置为String(认为参数类型可能与它有关),但是同样的结果,"id方法"总是命中.

I'm not great with regex, so the concept of determining a "best matching" regex is over my head. I may be wrong, but it appears this is what Jersey is doing. I tested also making the id parameter a String (thinking maybe the parameter type had something to do with it), but same result, the "id method" is always hit.

另一种选择,您可以进行简单的更改/或者可能有人称其为hack并执行类似的操作

Another option, you can make a simple alteration/or maybe some might call a hack and do something like

@GET
@Path("/{id: \\d+}{dummy: (/)?}")
public Response readSingleById(@PathParam("id") long id) {

基于第二个排序键(如上所述),排序后,"id方法"将始终位于"name方法"的前面.

Based on the second sort key (mentioned above), this would make the "id method" to always be in front of the "name method" after the sorting.

无论您决定如何,我都会确保进行彻底的测试.

Whatever you decide, I would make sure to do thorough testing.

就设计而言,您应该努力减少URI方案的模棱两可,但是我可以看到您的尝试,允许通过名称和ID查找资源.我个人对此没有很强烈的意见,但是您可以在 REST-同一资源的多个URI上找到很好的讨论(???)

As far as design, you should strive to make the URI schemes less ambiguous, but I can see what you are attempting, allowing a resource to be discovered by name and by id. I personally, don't have a strong opinion about this matter, but you can find a good discussion at REST - multiple URI for the same resource (???)

这篇关于JAX-RS如何匹配两个或多个兼容的@Path表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆