users@jersey.java.net

Re: [Jersey] Implementing a generic javax.ws.rs.core.Response

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 30 Mar 2009 17:45:39 +0200

On Mar 30, 2009, at 4:46 PM, Jaka JanĨar wrote:

> Hi!
>
> (disclaimer: this isn't really a question, just a request for
> comments of the idea)
>
> I want my resource methods to:
> a) return strongly typed entities (so entity types can be specified
> in interfaces), and
> b) have the ability to set status code, headers, etc.
>
> Returning Response violates (a), returning Other (in JAX-RS section
> 3.3.3 terms) prevents (b).
>
> Ideally, I would like my resource method to look something like this:
>
> @GET
> @Path("/person")
> MyResponse<Person> getPerson();
>

BTW we tried really hard to make Response generic, but gave up because
we could not make the generic type work correctly with the builder
pattern.


> So I thought about defining MyResponse as:
>
> public class MyResponse<T> extends javax.ws.rs.core.Response {
> public void setEntity(T entity) {...}
> public T getEntity() {...}
> ...
> }
>
> (btw, I think it's ugly that Response is an abstract class instead
> of an interface)
>

An abstract class was chosen because it makes it easier to extend
without breaking backward compatibility and it has the static builder
methods.


> But if I understand JAX-RS (table 3.1 in particular) correctly, this
> would break generic type recognition (it would fall in the 3rd row
> category), which I need in my entity providers.
>
> So the only solution, it appears, would be to define MyResponse in
> such a way that it would return GenericEntity:
>
> public class MyResponse<T> extends javax.ws.rs.core.Response {
> private T entity;
>
> public void setEntity(T entity) {...}
> public GenericEntity<T> getEntity()
> {
> return new GenericEntity<T>(entity) {};
> }
> ...
> }
>
> Does anyone see any problems with this?
>

Yes, you are not setting the genericType when creating the
GenericEntity thus things will not work for:

    MyResponse<List<Bean>>


> A concern I have is that, because I would like to stay Jersey-
> independent, I would have to implement MultivaluedMap (for
> Response#getMetadata()), but the implementations in Jersey seem to
> do much more than the trivial implementation of the interface, so
> I'm worried that something will break.
>

Note that the returned map may be modified by the runtime. Jersey's
implementation ensures that keys are case insensitive. If you do not
support case-insensitive keys things could be problematic.

I recommend you do the following. Create a dummy Response and use the
MultivaluedMap instance from that e.g.

    Response.ok().build().getMetadata()

Paul.