我无法到达正确的@Path

I cannot get to the correct @Path

使用 JAX-RS,我有以下 3 @Paths。

@Path(JobRest.PATH)
@Api(value = JobRest.PATH, description = "REST APIs for Jobs")
public interface JobRest {
    public static final String PATH = "/job";

    @GET
    @Path("/last")
    @Produces(MediaType.APPLICATION_JSON)
    public Job retrieveLastJob(...);

    @GET
    @Path("/{jobId}")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Job retrieveJob(...., @PathParam("jobId") String jobId, );

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public JobList retrieveAllJobs(....);
}

我预计 /job/last 会调用 retrieveLastJob(...),因为它匹配,但它会调用 retrieveJob(..., "last", ...)

如何更改符号以便 /job/last 调用 retrieveLastJob(...)

TL;DR

删除 retrieveJob 方法中的 @Consumes(MediaType.APPLICATION_JSON)。首先,它不接受 body,因此它不消耗任何东西。其次它与预期的行为冲突。


我已经用 Jersey 和 RESTeasy 进行了测试,这似乎在实现上有所不同。 Jersey 可以很好地处理您的代码,而 RESTeasy 总是会遇到 retrieveJob 方法,正如您遇到的那样。

这是我的看法。如果你看一下 JAX-RS spec; 3.7.2 Request Matching,有一个 semi-cryptic 匹配资源的算法,它是这样的。

  1. 获取所有匹配的资源class(按路径),将它们放入集合中。
  2. 获取所有匹配的资源方法(按路径),将它们放入集合中。
  3. 按最佳匹配路径对方法进行排序(大多数文字字符排在最前面)。
  4. 按媒体类型排序(使用消费和生产)。

从我的角度来看,在这种特殊情况下,在第 3 步之后,retrieveLastJob 应该会自动获胜,因为它具有最多的文字字符。生产媒体类型是相同的,消费媒体类型应该无关紧要,因为它是一个没有 Content-Type 进行任何匹配的 GET 请求。

我猜 RESTeasy 仍然使用注释来排序,即使在这种情况下甚至不应该考虑它。因此,带有注释的方法似乎具有更高的优先级,因为它 看起来 更具体,仅具有注释,而另一个则没有。但是在这种情况下(第 4 步)的特异性水平真的不重要。

我不知道这是否是违反规范的错误。目前还不太清楚应该如何处理,但我个人认为泽西岛的行为是正确的行为,因为在这种特殊情况下,这种特异性水平应该无关紧要。在任何情况下,对于没有 body.

的 GET 请求,无论如何使用 @Consumes 注释都是不正确的