jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: [jax-rs-spec users] Re: Re: Re: Allowing two resources to be mapped to the same URI

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Wed, 23 May 2012 11:24:25 +0100

On 23/05/12 11:16, Marek Potociar wrote:
>
> On May 22, 2012, at 7:44 PM, Bill Burke wrote:
>
>>
>>
>> On 5/22/12 1:16 PM, Marek Potociar wrote:
>>>
>>> On May 22, 2012, at 6:49 PM, Bill Burke wrote:
>>>
>>>>
>>>>
>>>> On 5/22/12 11:52 AM, Marek Potociar wrote:
>>>>>
>>>>> On May 22, 2012, at 3:06 PM, Bill Burke wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On 5/22/12 5:28 AM, Marek Potociar wrote:
>>>>>>>
>>>>>>> On May 21, 2012, at 10:35 PM, Bill Burke wrote:
>>>>>>>
>>>>>>>> I can see users wanting to add support for different formats in different resource classes. i.e.
>>>>>>>>
>>>>>>>> @Path("/root")
>>>>>>>> @Produces("application/xml")
>>>>>>>> public class MyRootXmlSupport {}
>>>>>>>>
>>>>>>>> @Path("/root")
>>>>>>>> @Produces("application/json")
>>>>>>>> public class MyJsonSupport {}
>>>>>>>>
>>>>>>>
>>>>>>> One of the main design concepts behind JAX-RS is that it should produce a representation independent model. The above use case just seems artificial to me and goes against the intended best practices.
>>>>>>>
>>>>>>
>>>>>> Whose best practices are you talking about? Its definitely not a bad practice, especially if there any media type formatting specific logic. Especially if your JAX-RS services are just a face over some EJB you are delegating to.
>>>>>
>>>>> JAX-RS best practices (see spec section 1.2 Goals - "Format independence") which are based on REST. Also a single URI should represent a single resource. The example above would be better modeled in JAX-RS as a single resource class and multiple entity providers. That plays well with OOD as well as JAX-RS/REST principles. The above is just poor design and a good example of why I would not want the spec to promote it as a standard.
>>>>>
>>>>
>>>> REST has really nothing to do with Java class design. And your assumptions are completely false that it as bad OOD too.
>>>
>>> I would disagree.
>>>
>>>> I've had plenty of users where their formatting requirements don't fit well with the whole MBR/MBW/JAXBContext/ObjectMapper/ContextResolver pattern and have had to do things more "manually" within a resource method. Also, many times people prefer to use Document + XPath as it gives them a lot of flexibility, rather than JAXB. They would of course use different APIs on the JSON side. It makes perfect sense to separate JSON from XML processing into separate classes in this case.
>>>
>>> Do the resource classes represent the same noun, same data? Do they produce same Java types? If not, why? And why they need to be on the same path? And how RESTful is that?
>>
>> REST has nothing to do with Java type system. The same URI may have different representations. Different representations may require different Java types. Finally, entity providers aren't always the best solution to the problem.
>
> That's why we have support for multiple java methods processing the same HTTP method right? And everything about the same resource remains nicely encapsulated in a single class.
>
>>
>>>
>>>> There's also the possibility of wanting to add support for a different media type to an existing library.
>>>
>>> That should be done via entity providers.
>>>
>>
>> If your resource method has a @Produces("application/xml") how are you supposed to do add support for Json if you can't change the implementation?
>
> You may need to wrap the resource into another one in such case. Not particularly nice, but how frequent is this use case? How often do you expose resource classes that you cannot modify?
>

I'd say that while it is actually nice to be able to expose the existing
legacy resources as services, and I've seen users liking it, it is
probably a bit of anti-pattern, having a wrapper specifically dedicated
to managing the HTTP invocations and introducing a bit of indirection
can be good

thanks, Sergey

>>>> Other users might want to separate read and write interfaces into separate classes.
>>>
>>> That's ok - entity providers have separate interfaces.
>>
>> Read - GET
>> Write - PUT, POST, DELETE
>
> Ok, this one is a bit more convincing.
>
>>>> In the JIRA case, the users just wants to have a separate class to implement his SEARCH requirements. That works well for his application and its arrogant to call his decisions bad practice or bad design where you have no idea what his code looks like.
>>>
>>> You may call it arrogant, but it is my right to voice my opinions in this forum. With the data that I have about the case I feel that the design smells. Maybe in the user's case after seeing the whole big picture it would not smell (or would smell less), I don't know. But the point is that in general I'm convinced this practice may lead to confusing designs and would actually back-fire in hands of perhaps less skilled users. Since the feature does not bring anything that could not be worked around and it is not a mainstream case, I don't see a sound reason for adding it to the spec.
>>>
>>
>> Hey, maybe SEARCH is an optional feature that requires a shit-load of extra code. Maybe he wants to offer that feature as a separate library.
>
> Yep - that is a valid use case (based also on the above).
>
>> To me, this isn't much different than having one EJB class for your JAX-RS interface and another EJB class for your JAX-WS interface.
>>
>>>>
>>>>> Now as for the second use case with OPTIONS support - that one would most certainly require use of back-tracking. Here I can only repeat that I am not going to support any change request that would require introduction of back-tracking into the matching algorithm.
>>>>>
>>>>
>>>> Spec language of "the matching algorithm does not require backtracking and thus applications may be required to provide less complex or more specific mappings to get around URI matching ambiguities."
>>>>
>>>> Is much better than the restriction of "You can only have one resource class mapping per URI".
>>>
>>> How does that relate to your options case? That would require back-tracking no matter what...
>>
>> Only a locator requires a backtrack. In our impl, a URI match may give a list of resource methods that match. Doesn't matter what classes these resource methods are in. We jsut loop through these matches to see which resource methods support the HTTP method and the Produces/Consumes.
>
> Well for me the matching does not involve just matching the URI. In the matching process you are doing lots of complex processing in any of these phases:
>
> 1. match URI
> 2. match HTTP method
> 3. match consumed/produced media types
>
> If any of the phases requires stepping a level up, for me it is a back tracking. The point of the current matching algorithm is exactly to avoid the need for doing that. In Jersey we also use the approach that URI matching in phase 1 produces a list of methods that are further filtered in phases 2& 3. Same as in your impl, it does not matter what class the method belongs to (which is why I said in the beginning that it is not a problem for us to support the issue implementation-wise). However, if there is no method found after phase 1, 2& 3 are finished, we do not back-track and repeat the same process with another resource URI in the list. And that's also something I don't want to be forced to do.
>
>>
>> Hey, I've given you a bunch of different reasons why I might want to ahve multiple classes map to the same URI. Do what you will, but please don't add a TCK test to enforce it if you decide to keep this restriction.
>
> Ok, with the split read/write/search use cases above I am more inclined to change the spec to support the proposal from the issue. But just to be clear - this is what would be supported:
>
> @Path("a/b")
> public class A { get }
>
> @Path("a/b")
> public class B { put, post, delete }
>
> @Path("a/b")
> public class C { search }
>
> In the case above, the GET, PUT, POST, DELETE and SEARCH would all be supported for "a/b" resource.
>
> However, following would not be supported:
>
> @Path("a/b")
> public class A { get }
>
> @Path("{path: .*}")
> public class B { options }
>
> In the example above the OPTIONS "a/b" would still return 405, because while both "a/b" and "(.*)" path templates match "a/b", those are not the same paths and runtime would not merge A& B methods under the same path template. Supporting this case would thus require back-tracking, which would be a showstopper.
>
>> BTW, is this illegal too?
>>
>> @Path("/foo/{blah :.*}")
>> public class A {}
>>
>> @Path("/foo/bar")
>> public class B {}
>
> No, it is not illegal, why should it be? Those are not the same URI templates. But if your B implements GET and your A implements POST, the algorithm will return 404 for a POST "/foo/bar" request because it will first match B where the POST is not defined. It will not try to back-track and match also A.
>
> Note that if your impl would find POST in this case, you are violating the spec and your users may be unintentionally writing non-portable JAX-RS applications. Which is why I think that this case should be covered by TCK tests (if it is not already, as it is one of the MUSTs of the spec - sect. 3.7) and if you want to support such constructs and pass TCK, you may need to implement a compatibility switch.
>
> Marek
>
>>
>> --
>> Bill Burke
>> JBoss, a division of Red Hat
>> http://bill.burkecentral.com
>