[jax-rs-spec users] Re: _at_Path with regular expression overrides other @Path's with the same URI

From: Bill Burke <>
Date: Fri, 16 Oct 2015 11:00:53 -0400

I bet you can count on one hand the users that wanted plug in their own
matching strategy. Personally, I just can't justify that amount of work
just to satisfy a very small handful of users.

Supporting backtracking allows support for some very simple use cases
that I get asked about all the time.

I've argued in the past that supporting backtracking does not break
backward compatibility. Marek and Santiago disagreed...Thus here we are.

On 10/16/2015 10:31 AM, Sergey Beryozkin wrote:
> Bill, I'd say it is a bit too strong.
> I've had many users in CXF successfully using a custom matching
> strategy, for example, before 2.0 spec improved the selection between
> multiple matching class resources on the same path, when choosing
> between multiple equal candidates based on a number of query/etc
> parameters, etc.
> I'm all for improving the algorithm. But I somehow suspect that a
> strategy path can make improving the algo more realistic as there will
> be a two-way link.
> Sergey
> On 16/10/15 15:13, Bill Burke wrote:
>> On 10/15/2015 5:09 PM, Markus KARG wrote:
>>> What about adding the ability for an application to provide a
>>> MatchingStrategyProvider?
>> I can't see anybody ever wanting to write one. So -1000.
>>> Like simply packing a POJO in the WAR file that is annotated by
>>> @Provider and implements any custom algorithm wanted? That way we
>>> could keep the spec as-is, and Bill and Sergey could simply wrap
>>> their existing "non-compliant but intuituve" algorithms as .class
>>> files, so developers can put that .class file into their WAR and have
>>> a WORA solution.
>>> Feasible?
>> -1000. Fix the spec. There's really no reason not to support
>> backtracking in the matching algorithm. It makes zero sense to
>> return 405 or 404 responses when there is a resource method that could
>> be matched by backtracking. Furthermore, it is highly doubtful that
>> backtracking would break existing Jersey apps as these apps don't rely
>> on backtracking. IMO, this change would be akin to adding a method to
>> an interface.
>> This simple program shows how silly the matching algorithm is:
>> @Path("/doc.txt")
>> @GET
>> @Path("/doc.pdf")
>> @GET
>> @Path("/{document}")
>> It is a well known best practice to use URLs rather than content
>> negotiation. Yet, in this simple program, the user would also have to
>> write explicit @DELETE methods for doc.txt and doc.pdf even though a
>> catch all would work just fine.
>> Here's some other ones too:
>> Resteasy changed its matching algorithm prior to the JAX-RS 2.0 TCK
>> specifically because users asked us to.
>>> -Markus
>>> -----Original Message-----
>>> From: Bill Burke []
>>> Sent: Donnerstag, 15. Oktober 2015 15:52
>>> To:
>>> Subject: Re: [jax-rs-spec users] @Path with regular expression
>>> overrides other @Path's with the same URI
>>> The right thing to do is to improve the matching algorithm. I could
>>> also refer you to a bunch of "bug" reports where people are complaining
>>> about the matching algorithm. I then have to explain to them that this
>>> isn't a "bug" but a "feature". I also must say that there are far fewer
>>> ISVs than regular JAX-RS developers that stick to one implementation.
>>> Changing the TCK for one edge case that may break 2 different products
>>> that are 7+ years old with thousands upon thousands of downloads doesn't
>>> sound like the best way to make Java EE developers happy.
>>> It is Jersey and the spec that should change. Changing the matching
>>> algorithm will in most cases effect no Jersey users.
>>> On 10/15/2015 8:11 AM, Marek Potociar wrote:
>>>> Hi Sergey,
>>>> Well, the discussion on the Jersey thread clearly shows how
>>>> confusing it is if the implementations are not 100% compliant with
>>>> the spec. You either are compliant or you are not. There are no
>>>> shades of gray when it comes to official spec compliance. If you
>>>> pass TCK, you are compliant, if you don’t you are not. If there is a
>>>> hole in TCK coverage, it may get fixed later and then you would need
>>>> to pass the fixed TCK to be compliant.
>>>> The standard specifications are here to ensure application
>>>> portability for users. From the user perspective a pure JAX-RS code
>>>> must behave the same way on ANY implementation that claims to be
>>>> JAX-RS compliant.
>>>> Marek
>>>>> On 15 Oct 2015, at 01:03, Sergey Beryozkin <>
>>>>> wrote:
>>>>> Hi Markus
>>>>> I'd like to refer to the other thread where you agreed we should
>>>>> not rush it.
>>>>> Yes, as it currently stands - RestEasy and CXF are not compliant in
>>>>> this specific case.
>>>>> However IMHO we should strive really hard not to treat such cases
>>>>> as this is how it should and that is it.
>>>>> I think it is more of a spec text being non-intentionally too
>>>>> strict in this case - lets give it a chance - if Santiago can find
>>>>> an opportunity to 'fix' it then we will all win, if not then at
>>>>> least we gave it another try
>>>>> Cheers, Sergey
>>>>> On 14/10/15 21:41, Markus KARG wrote:
>>>>>> Sergey,
>>>>>> I understand your arguments, but for users (and for TCK)
>>>>>> compliance is a true/false question. As an ISV I need to rely on
>>>>>> the fact that matching works exactly the same on all
>>>>>> implementations (at least as long the spec does not provide a
>>>>>> means for an application to provide its own matching algorithm).
>>>>>> So what do we tell people now? They wait for an answer. Are
>>>>>> CXF/RestEasy definitively non-compliant or not?
>>>>>> -Markus
>>>>>> -----Original Message-----
>>>>>> From: Sergey Beryozkin []
>>>>>> Sent: Montag, 12. Oktober 2015 22:33
>>>>>> To:
>>>>>> Subject: Re: @Path with regular expression overrides other @Path's
>>>>>> with the same URI
>>>>>> Hi Santiago
>>>>>> I was thinking on the way home, I thought the sentence where the
>>>>>> 'M' set is built from Rmatch = R(Td) is a bit strict.
>>>>>> I recall the explicit regular expressions were added at the last
>>>>>> moment in 1.0, the current text covers a situation with same verbs
>>>>>> OK (in that Jersey issue I thought there were two GETs where I'd
>>>>>> indeed expect the method with an explicit reg expression win)...
>>>>>> Rmatch = R(Td) condition blocks a GET method from being included
>>>>>> in M (referring to that example).
>>>>>> I suspect replacing a '=' symbol with another one implying Rmatch
>>>>>> is equal or equivalent to R(Td).
>>>>>> I suspect I might've got confused with my analysis above but I
>>>>>> open an issue
>>>>>> Markus, I'm not sure the fact CXF/Reasteasy would not select
>>>>>> DELETE makes either implementation broken :-).
>>>>>> My opinion the spec text is far from being perfect in this
>>>>>> specific case which I agree makes CXF/RestEasy is not compliant
>>>>>> here but perhaps in this case the spec text can be optimized
>>>>>> before a new TCK test is added :-).
>>>>>> Thanks, Sergey
>>>>>> On 12/10/15 19:22, Santiago Pericasgeertsen wrote:
>>>>>>>> On Oct 12, 2015, at 1:03 PM, Markus KARG
>>>>>>>> <> wrote:
>>>>>>>> Sergey,
>>>>>>>> so what is the conclusion now? CXF is broken and you will fix it?
>>>>>>> Let’s file it as an issue and review it later. I had a quick
>>>>>>> look at the algorithm and, frankly, it is not as clear as I hoped
>>>>>>> so but I don’t have the cycles to look at it deeper at this point.
>>>>>>> — Santiago
>>>>>>>> -----Original Message-----
>>>>>>>> From: Sergey Beryozkin []
>>>>>>>> Sent: Montag, 12. Oktober 2015 17:26
>>>>>>>> To:
>>>>>>>> Subject: Re: @Path with regular expression overrides other @Path's
>>>>>>>> with the same URI
>>>>>>>> Hi Santiago
>>>>>>>> That long discussion we last had, that was related to a case
>>>>>>>> where a
>>>>>>>> matching subresource locator was discarded, even though it was
>>>>>>>> having
>>>>>>>> a matching method, as opposed to the current resource class.
>>>>>>>> It still 'hurts' whenever I think about it.
>>>>>>>> But in this case it is different, no backtracking of any sort is
>>>>>>>> even
>>>>>>>> needed here - it is so simple...
>>>>>>>> So we are at "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), the
>>>>>>>> number of capturing groups with non-default regular expressions
>>>>>>>> (i.e.
>>>>>>>> not
>>>>>>>> '([^/]+?)') as the tertiary key
>>>>>>>> (descending order)..."
>>>>>>>> Then yeah, DELETE is supposed to be selected. This is so sad. The
>>>>>>>> only consolation, regular expressions are not that popular...
>>>>>>>> Sergey
>>>>>>>> On 12/10/15 14:31, Santiago Pericasgeertsen wrote:
>>>>>>>>> All,
>>>>>>>>> First, obviously I agree the result is counter-intuitive.
>>>>>>>>> Second,
>>>>>>>>> we
>>>>>>>> have had this this discussion many in the times in the past ;), and
>>>>>>>> basically the same algorithm since JAX-RS 1.0 AFAIK. Third, the
>>>>>>>> algorithm does not backtrack or look ahead, and thus makes a
>>>>>>>> decision
>>>>>>>> first on Path and then on method resulting in the observed behavior
>>>>>>>> -because it discarded potential matches too soon.
>>>>>>>>> If an implementation behaves differently, it is because it is
>>>>>>>> implementing a different algorithm from the one in the spec.
>>>>>>>> Ideally
>>>>>>>> we should change the algorithm, but unfortunately it is not a
>>>>>>>> backward compatible change.
>>>>>>>>> - Santiago
>>>>>>>>>> On Oct 12, 2015, at 9:08 AM, Sergey Beryozkin
>>>>>>>>>> <>
>>>>>>>> wrote:
>>>>>>>>>> Oh, that is actually completely broken, I agree, I thought there
>>>>>>>>>> were two
>>>>>>>> GET methods there, my fault.
>>>>>>>>>> I honestly can not see how that can be resolved as works as
>>>>>>>>>> expected...
>>>>>>>>>> Sergey
>>>>>>>>>> On 12/10/15 14:00, Bill Burke wrote:
>>>>>>>>>>> If this is true, then the matching algorithm is showing yet
>>>>>>>>>>> again,
>>>>>>>>>>> how
>>>>>>>> effed up it is. The @Get method in the example should always
>>>>>>>> resolve. It makes sense intuitively. In Resteasy if the @Delete
>>>>>>>> path
>>>>>>>> resolved first, but the methods didn't match, we would
>>>>>>>> "backtrack" and try the get method.
>>>>>>>>>>> On 10/11/2015 12:00 PM, Sergey Beryozkin wrote:
>>>>>>>>>>>> Jersey is correct in that example - a template var with a regex
>>>>>>>>>>>> wins over a basic template var.
>>>>>>>>>>>> The spec clearly states that an expression with more literal
>>>>>>>>>>>> chars
>>>>>>>> wins.
>>>>>>>>>>>> So I guess a regex expression can only win if, besides the
>>>>>>>>>>>> rex-ex
>>>>>>>>>>>> expression itself, a given path has more literal chars, say,
>>>>>>>>>>>> abc[d|e] would win over abc - I think this can only happen when
>>>>>>>>>>>> choosing between multiple matching root resources.
>>>>>>>>>>>> Or it can win in that Jersey JIRA issue - a number of literal
>>>>>>>>>>>> chars beyond the regex is equal but the regex method wins
>>>>>>>>>>>> because
>>>>>>>>>>>> a template var is more specific. I'll double check with CXF - I
>>>>>>>>>>>> doubt it works
>>>>>>>> diff
>>>>>>>>>>>> in CXF
>>>>>>>>>>>> Sergey
>>>>>>>>>>>> On 11/10/15 08:28, Markus KARG wrote:
>>>>>>>>>>>>> Experts,
>>>>>>>>>>>>> in a discussion on the Jersey user group someone claimed that
>>>>>>>>>>>>> the behaviour of Jersey is different from CXF and RestEasy. As
>>>>>>>>>>>>> that would imply both, an inaccuracy of the TCK (it does not
>>>>>>>>>>>>> detect the
>>>>>>>>>>>>> deviation) and a violation of the specification in CXF and
>>>>>>>>>>>>> RestEasy (as Jersey is the RI, hence axiomatically cannot be
>>>>>>>>>>>>> wrong), we should quickly clarify the truth in that claim.
>>>>>>>>>>>>> The case is recorded in Jersey's issue tracker including
>>>>>>>>>>>>> source
>>>>>>>>>>>>> code
>>>>>>>>>>>>> ( and is simple to
>>>>>>>>>>>>> explain:
>>>>>>>>>>>>> *Given a resource has two methods, annotated as **_at_GET
>>>>>>>>>>>>> @Path(//<PathParam>/) and **_at_DELETE @Path(//<RegEx>/)*
>>>>>>>>>>>>> *When a client invokes **GET <RootURI>//<PathParam>/ upon that
>>>>>>>> resource*
>>>>>>>>>>>>> *Then the result is **405 Method Not Allowed*
>>>>>>>>>>>>> While this looks pretty odd to the average Joe (as there is a
>>>>>>>>>>>>> perfect match of GET and /<PathParam>/), it was claimed that
>>>>>>>>>>>>> this is _compliant_ to the specification (since regex have
>>>>>>>>>>>>> higher priority than literals, and methods are matched
>>>>>>>>>>>>> after URIs).
>>>>>>>>>>>>> It was reported that CXF and RestEasy return 200 OK instead,
>>>>>>>>>>>>> while the RI does return 405 Method Not Allowed.
>>>>>>>>>>>>> Certainly an application MUST return the same status code
>>>>>>>>>>>>> on ANY
>>>>>>>>>>>>> JAX-RS compliant implementations, so we should clarify ASAP
>>>>>>>>>>>>> the
>>>>>>>>>>>>> following questions:
>>>>>>>>>>>>> (1) @SpecLeads: Is the use case described above (regex beats
>>>>>>>>>>>>> literals) really compliant to the JAX-RS specification, and
>>>>>>>>>>>>> how
>>>>>>>>>>>>> to explain /to the average Joe/ the reasonability of ignoring
>>>>>>>>>>>>> the apparently perfect match?
>>>>>>>>>>>>> (2) @SpecLeads: Is there a bug in the TCK so it does not
>>>>>>>>>>>>> detect
>>>>>>>>>>>>> the deviation of CXF and RestEasy?
>>>>>>>>>>>>> (3) @Vendors: Can you please check your implementations
>>>>>>>>>>>>> whether
>>>>>>>>>>>>> they really violate the spec? Do you have plans to fix it?
>>>>>>>>>>>>> I think we all have a vital interest in clarifying it, as a
>>>>>>>>>>>>> standard makes only sense when it is reasonable and commonly
>>>>>>>>>>>>> accepted, so I would be glad if you could answer the above
>>>>>>>>>>>>> points rather soon. :-)
>>>>>>>>>>>>> Thanks
>>>>>>>>>>>>> -Markus

Bill Burke
JBoss, a division of Red Hat