users@jersey.java.net

Re: Resources and subresources

From: Richard Wallace <rwallace_at_thewallacepack.net>
Date: Thu, 29 Nov 2007 22:01:25 -0800

Ok, so I jumped the gun a little again. I was using 0.5-ea but I just
updated to the latest trunk build and things are better. My
getBookmark(@UriParam("uri") uri) is no longer getting the full path,
it's getting just the parameter part.

I also I finally figured out why my BookmarksResource wasn't getting
used. I was trying to hit

http://localhost:8080/spike/bookmarks/

instead of

http://localhost:8080/spike/bookmarks

Hitting the first results in the BookmarkResource being called with an
empty string for the uri. Hitting the second does the right thing. Not
the most intuitive behavior, but now that I know what to look out for...

Richard Wallace wrote:
> Alright, well it looks like I spoke too soon. I tried using the
> following as you suggested:
>
> @UriTemplate("bookmarks")
> public class BookmarksResource { ... }
>
> @UriTemplate("bookmarks/{uri}")
> public class BookmarkResource { ... }
>
> with the uris
>
> http://localhost:8080/spike/bookmarks/http://google.com
> http://localhost:8080/spike/bookmarks
>
> But this seems to be even more broken. Now my
>
> @HttpMethod("GET") BookmarksResource.getBookmarks()
>
> still never gets called. Instead the
>
> @HttpMethod("GET") BookmarkResource.getBookmark(@UriParam("uri") uri)
>
> is _always_ called, and when it does get called, the value of the uri
> param is "bookmarks" or "bookmarks/http://google.com". For some
> reason it's using the path for the parameter!
>
> What am I screwing up now?
>
> Rich
>
> Richard Wallace wrote:
>> Awesome. Thanks for the response. That is exactly what I was hoping
>> for.
>>
>> Rich
>>
>> Marc Hadley wrote:
>>> On Nov 28, 2007, at 12:52 AM, Richard Wallace wrote:
>>>>
>>>> I've been playing with with resources and subresources and was
>>>> trying to fit in with the way the JSR311 spec works. So, you have
>>>> root resources that return subresources. What I was hoping to do
>>>> was get an instance of a ResourceFactory to create the the resource
>>>> to return. Unfortunately, the createResource() method needs the
>>>> resource features and properties from the ResourceConfig which I
>>>> don't have. I was then hoping to just use my Guice injector to
>>>> create the resource, but I don't have access to the ServletContext
>>>> (well, I can, but it's an ugly hack).
>>>>
>>>> What I tried next is the way I would prefer to create my
>>>> resources. That is to annotate each resource with the @UriTemplate
>>>> that it handles. So for a list of all bookmarks and then a single
>>>> bookmark I'd have resources like:
>>>>
>>>> @UriTemplate("/")
>>>> public class BookmarksResource { ... }
>>>>
>>>> @UriTemplate("/{uri}")
>>>> public class BookmarkResource { ... }
>>>>
>>>> With this pattern I don't have to worry about creating
>>>> BookmarkResource instances from BookmarkResource and injecting all
>>>> the right values. It would also make deeper hierarchies easier to
>>>> build because I'm not sure how it's intended to be done, but from
>>>> my understanding hitting a resource with a path of
>>>> /bookmarks/{uri}/comments/{comment-id} would require the
>>>> BookmarksResource to be created, which would create a
>>>> BookmarkResource, which would create a CommentsResource which would
>>>> finally create a CommentResource that is returned. That means you
>>>> could need to inject a whole bunch of dependencies into your root
>>>> level resource so they can trickle down to the deeper resource
>>>> objects. I'd much rather have all my resources created equally.
>>>>
>>> If you're resources are such that you can use a URI template to
>>> identify them then that is definitely the way to go rather than
>>> using sub-resources. Sub-resources are there to handle cases where
>>> the URI path is somewhat dynamic or when the same resource can be
>>> found at multiple paths (though you can always create a subclass for
>>> each and then still use a template).
>>>
>>>> I had thought this might still work even if it seems to go against
>>>> the grain of JSR311, but found that it doesn't.
>>>
>>> Its not against the grain of 311, that is how it is supposed to be
>>> used for the majority of cases. I think you've just run into an
>>> issue using '/' as a template. The value of @UriTemplate is a
>>> relative URI whose base URI is supplied by the deployment context. I
>>> suspect we may have an issue dealing with what is effectively an
>>> empty template.
>>>
>>>> What happens is that when I hit
>>>> http://localhost:8080/spike/http://google.com, everything works as
>>>> expected. But when I try and hit http://localhost:8080/spike/, I
>>>> get a 500 response with a message that says "The "Content-Type"
>>>> header is set to text/xml, but the response has no entity". After
>>>> doing some digging it seems this is because for the / path the
>>>> BookmarkResource is being used instead of the BookmarksResource.
>>>> Because the uri is empty no bookmark is found and null is returned.
>>>>
>>>> There were 2 things unexpected about this. The first was that
>>>> BookmarkResource was being used, which I'll get to in a minute.
>>>> The second is that returning null resulted in a 500. My
>>>> expectation was that returning null would indicate a 404, because
>>>> the resource at the location could not be found. To me, that's
>>>> really the only reason a method annotated with @HttpMethod would
>>>> ever return null, is if there was nothing to return. Otherwise it
>>>> would throw an exception.
>>>>
>>>> Getting back to the issue at hand, I did some more digging to find
>>>> out exactly how it was being decided that the BookmarkResource
>>>> should handle / instead of the BookmarksResource. What I found was
>>>> that the rule for matching the BookmarkResource was being checked
>>>> first and was using the regex /(.*?)(/)?, or something similar,
>>>> that's from memory. The important part is the /.* bit. This means
>>>> the BookmarkResource will be matched for anything. That would
>>>> solve this problem. Is there any ordering going on when the
>>>> resources are being added, or are they simply matched in the order
>>>> they're found when scanning? If there is an order, shouldn't the
>>>> rule for the BookmarksResource be first, since it is less
>>>> specific? If there isn't any ordering being done, don't you think
>>>> there probably should be?
>>>>
>>> Matching resources are sorted using the number of literal characters
>>> (i.e. those not resulting from template variables) as the primary
>>> key and the number of template variables as the secondary key.
>>>
>>> I think if you changed your template to be something like:
>>>
>>> @UriTemplate("bookmarks")
>>> public class BookmarksResource { ... }
>>>
>>> @UriTemplate("bookmarks/{uri}")
>>> public class BookmarkResource { ... }
>>>
>>> with the uris
>>>
>>> http://localhost:8080/spike/bookmarks/http://google.com
>>> http://localhost:8080/spike/bookmarks
>>>
>>> then everything would be OK.
>>>
>>> Marc.
>>>
>>> ---
>>> Marc Hadley <marc.hadley at sun.com>
>>> CTO Office, Sun Microsystems.
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>