users@jersey.java.net

[Jersey] Re: Root resource as a resource factory (to handle @Path("/") as well)

From: Martynas Jusevičius <martynas_at_graphity.org>
Date: Fri, 12 Oct 2012 18:16:14 +0300

Gili,

I was looking at resource factory as a way to achieve polymorphism as
I actually have 2 interfaces: Resource and ContainerResource that
extends Resource. So my plan was to have getResource() like this:

@Path("/")
class RootResource
{
  @Path("{path: .*}")
  public Resource getResource()
  {
    Resource resource = new ResourceBase();
    if (resource.canBeContainer()) resource = new
ContainerResourceBase(resource);
    return resource;
  }
}

But you're right, I can have the root resource handling all cases
without sub-resources and achieve the polymorphism inside its
constructor:

@Path("{path: .*}")
class RootResource implements Resource
{
  private Resource resource = null;

  public RootResource()
  {
    resource = new ResourceBase();
    if (resource.canBeContainer()) resource = new
ContainerResourceBase(resource);
  }

  @GET
  public Response get()
  {
    // implementation reuse
    return resource.get();
  }

  // other Resource methods
}

I think this is less elegant, but at least it shouldn't have the issue
with handling @Path("/") case.

Martynas
graphity.org

On Fri, Oct 12, 2012 at 5:26 PM, cowwoc <cowwoc_at_bbs.darktech.org> wrote:
>
> Can't you get the RootResource to handle all requests itself, as opposed
> to having a sub-resource in the first place?
>
> Gili
>
>
> On 12/10/2012 10:21 AM, Martynas Jusevičius wrote:
>>
>> Hey Gili,
>>
>> I've come to a similar conclusion, but I think this is a limitation
>> however. I think root resources should be able to function simply as
>> resource factories -- also in case of @Path("/").
>>
>> If RootResource has to implement Resource interface for example, which
>> not only contains @GET get(), but also @POST post() and some more
>> methods, your example doesn't look so elegant anymore -- probably smth
>> like this:
>>
>> @Path("/")
>> public class RootResource implements Resource
>> {
>> private Resource resource = null;
>>
>> public RootResource()
>> {
>> resource = getResource();
>> }
>>
>> @GET
>> public Response get()
>> {
>> // implementation reuse
>> return resource.get();
>>
>> }
>>
>> @POST
>> public Response post()
>> {
>> // implementation reuse
>> return resource.post();
>>
>> }
>>
>> // some more methods wrapping this.resource
>>
>> @Path("{path: .*}")
>> public Resource getResource()
>> {
>> return new Resource();
>> }
>> }
>>
>> But there doesn't seem to be a better way?
>>
>> Martynas
>> graphity.org
>>
>> On Fri, Oct 12, 2012 at 4:40 PM, cowwoc <cowwoc_at_bbs.darktech.org> wrote:
>>>
>>> Hi Martynas,
>>>
>>> My guess is that what you're trying to do won't work, because the
>>> entire
>>> point of @Path is to say "the current resource handles *this* path". Now,
>>> if
>>> you really want the sub-resource to handle it, and there is no such thing
>>> as
>>> a parent of "/" then the only way to handle this is declare
>>> @GET/_at_POST/etc
>>> inside RootResource and delegate to getResource(). For example:
>>>
>>>
>>> @Path("/")
>>> public class RootResource
>>> {
>>> @GET
>>> public Response get()
>>> {
>>> // implementation reuse
>>> return getResource().get();
>>>
>>> }
>>>
>>> @Path("{path: .*}")
>>> public Resource getResource()
>>> {
>>> return new Resource();
>>> }
>>> }
>>>
>>> I've done something similar in my own code, for different reasons.
>>> One
>>> benefit of this approach is that type-safety remains enforced at
>>> compile-time. If the sub-resource ever changes in a way that requires
>>> RootResource to change you are likely to get a compiler error.
>>>
>>> Gili
>>>
>>>
>>> On 12/10/2012 6:31 AM, Martynas Jusevičius wrote:
>>>>
>>>> Marek,
>>>>
>>>> sorry, this is a typo left from when I tried to split the sub-resource
>>>> locators into 2 -- one for the base URI and one for the rest.
>>>>
>>>> The following code has the same effect (HTTP Status 405 - Method Not
>>>> Allowed):
>>>>
>>>> @Path("/")
>>>> public class RootResource
>>>> {
>>>>
>>>> @Path("{path: .*}")
>>>> public Resource getResource()
>>>> {
>>>> return new Resource();
>>>> }
>>>>
>>>> }
>>>>
>>>> BTW, I'm using Jersey 1.9 -- maybe there have been some bugs in this
>>>> area?
>>>>
>>>> Martynas
>>>>
>>>> On Fri, Oct 12, 2012 at 1:22 PM, Marek Potociar
>>>> <marek.potociar_at_oracle.com> wrote:
>>>>>
>>>>> On Oct 12, 2012, at 9:10 AM, Martynas Jusevičius
>>>>> <martynas_at_graphity.org>
>>>>> wrote:
>>>>>
>>>>>> Hey again,
>>>>>>
>>>>>> how can turn a single root resource into a resource factory that
>>>>>> handles all requests through sub-resource locators -- *including* the
>>>>>> base URI @Path("/")?
>>>>>> I tried the following but I get 405 Method not allowed:
>>>>>>
>>>>>> @Path("/")
>>>>>> public class RootResource
>>>>>> {
>>>>>>
>>>>>> @Path("{path: .+}")
>>>>>> public Resource getResource()
>>>>>> {
>>>>>> return new Resource();
>>>>>> }
>>>>>>
>>>>>> }
>>>>>>
>>>>>> I guess Jersey expects @GET etc. on the RootResource -- but I want
>>>>>> @Path("/") to be handled by getResource() as well.
>>>>>> I haven't found any requirements for root resources to contain
>>>>>> resource methods e.g. GET - but maybe @Path("/") is a special case?
>>>>>>
>>>>> Your regular expression seems to require at least one character. Try to
>>>>> replace it with "{path: .*}".
>>>>>
>>>>> Marek
>>>>>
>>>>>
>>>>>> Is this possible with JAX-RS/Jersey?
>>>>>>
>>>>>> I found a very similar dynamic dispatching example in the book
>>>>>> "RESTful Java with JAX-RS" -- however not with the base @Path("/"):
>>>>>>
>>>>>> @Path("/customers")
>>>>>> public class CustomerDatabaseResource {
>>>>>> protected CustomerResource europe = new CustomerResource();
>>>>>> protected FirstLastCustomerResource northamerica =
>>>>>> new FirstLastCustomerResource();
>>>>>> @Path("{database}-db")
>>>>>> public Object getDatabase(@PathParam("database") String db) {
>>>>>> if (db.equals("europe")) {
>>>>>> return europe;
>>>>>> }
>>>>>> else if (db.equals("northamerica")) {
>>>>>> return northamerica;
>>>>>> }
>>>>>> else return null;
>>>>>> }
>>>>>>
>>>>>> Martynas
>>>>>> graphity.org
>>>
>>>
>