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
>