users@jersey.java.net

Re: First hurdles

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 26 Nov 2007 09:42:10 +0100

Richard Wallace wrote:
> Hello,
>
> So I'm getting over my first hurdles using Jersey and just thought I'd
> give a bit more feedback. After figuring out that the issue with the
> scanning was because I was trying to run the webapp inplace with Jetty
> my next challenge was actually getting it to do something. I like the
> idea of having a provider to generate the response. But it's quite a
> pain for it to have to be specified in a file in the META-INF/services
> directory. Because of this I wound up having to split my webapp and my
> REST classes into separate projects because otherwise I couldn't get the
> dang things in the right place for the class loader to find it.
>

We are going to change this for 0.6 so that:

1) instances of reader/writer are scopped per the application; and

2) there is a way other than META-INF/services for users to register
    their own readers/writers e.g. using something like resource class
    discovery or passing in instances as a property of the
    ResourceConfig.


> I understand there is some work going on to get better view handling
> better, so let me second (or third or whatever I would be) getting
> Freemarker integrated.
>

Good to know. We will concentrate on JSP/JSTL and Freemarker.


> Something else I was wondering was what the best to declare a
> MessageBodyWriter for a Collection of objects. Naturally I'd really
> like to be able to just have a method in my resource like
>
> @HttpMethod("GET")
> @ProduceMime("text/plain")
> public List<Bookmark> getBookmarks() {
> return ...;
> }
>
> and a provider like
>
> @Provider
> @ProduceMime("text/plain")
> public class BookmarksProvider implements MessageBodyWriter<BookmarkList> {
>
> public boolean isWriteable(Class<?> clazz) {
> return List<Bookmark>.class.isAssignableFrom(clazz);
> }
>
> ...
> }
>
> Naturally that doesn't work because of erasures. So what I've instead
> done is create a BookmarksList that implements List<Bookmark> and just
> delegates to whatever actual List object is used to construct it. For
> this simple spike it's pretty easy to do, but if my domain model was
> larger managing all these extra List classes would be a major pain. I
> don't know what the best solution is for this (other than pushing for
> reified generic types that is), but maybe something as simple as adding
> annotations to the resource method indicating what the MessageBodyWriter
> or MessageBodyReader is for that method.
>

Yes, you have highlighted a very frustrating area. Florian (in other
messages on this list) wrote something similar (using the old
'EntityProvider' interface) for writing collections of JAXB elements.

Specifying the reader/writer as annotations for these special cases
would work, although it annoys me that we would have to resort to that :-)

Note that readers/writers can now be scoped with Produce/ConsumeMime so
it is possible to limit such readers/writers to particular media types.
But still that does not solve the general issue.

One way we can sort of do this is by having the writer method:

     Writer.supports(Class<?> c, Object o)

that at least the contents of the list can be verified. But still... and
something similar for reader:

     Reader.supports(Class<?> c, Type t)

with type information extracted from the method signature.

It needs some more discussion in the 311 EG.


> One other thing that I noticed in the HttpResponseAdaptor.commitAll()
> method that the status code is set and then the MessageBodyWriter
> provider is called. So, if there is an exception when creating the
> response body, such as an exception when parsing a Freemarker template,
> the client will get a 200 even though the response is going to be
> incomplete, if not completely invalid. I understand that this would
> most likely be caused by a bug in the template or provider, but it would
> make tracking down the problem much easier if the client got a 500.
>

This is also, in general, a trade off between buffering and streaming. I
would prefer not to enforce that all Jersey containers have to buffer
the bytes of what is written so as to catch exceptions when writing (the
underlying container may or may not buffer).

I am not sure the client will get a 'correct' 200 response because, in
the case of the LW HTTP server a RuntimeException or an IOException will
be passed to the server, that is likely to terminate the connection or
produce invalid response due to an Content-Length or chunked encoding
validation error (i hope the former).

Hmm... but for views support allowing buffering does seem to be useful
to report 500 errors as for some template engines code 'leaks' into the
template.

I think we at least need to document the traps that writer developers
need to be aware of. And it may be possible for writers to do their own
buffering by Jersey supporting an implicit commit of the status and
headers when the first byte to the OutputStream passed to the writer is
written.


> Now I'm off to play with getting Guice working as per Christians blog.
> Wish me luck!
>

Good luck!

Paul.

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109