users@jsr311.java.net

Re: jax-rs design opportunities

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Tue, 19 Jan 2010 17:26:02 -0500

On Jan 19, 2010, at 4:57 PM, Monte Hansen wrote:

> I posted this to the public jsr 311 board back in November, but the board appears to be a ghost town, so I submit same to the mailing list.

Sorry, I never saw it.

> I'm a huge fan of REST and jax-rs so please accept this with the spirit from which it is intended. I've been using jax-rs for a while now while trying to revamp my own REST library to conform to jsr 311. It hasn't been easy to conform due to one limiting factor: ResponseBuilder.
>
> Actually, my concerns aren't so much what I "can" do with ResponseBuilder, but rather, what I "can't do" without out it. For instance, cache control, response encoding, template-based processing (xsl/fo/xqj), etc – such things are painful or impossible to control or provide within the specification without using ResponseBuilder, and leave too much room for variance to implementation.
>
> The idea of exposing an operation as a REST resource is large. Moreover, reusability of those operations is larger still. That's why an operation that returns a type of javax.ws.rs.core.Response has no place in my world, or to any who aspire to write generic entities that can be consumed internally (pojo), or exposed externally as a resource uri. Using the ResponseBuilder hard-wires the method to a web response and limits the ability to reuse the method generically. This is a contradiction to the specification's first stated POJO-based goal. Both the specification and documentation tend to lead the author to use ResponseBuilder as a "red-carpet" inference, when it should (IMO) empower the Provider so that it isn't even necessary, allowing for better separation and reusability. So, those that stick to their design principals are penalized by not being able to control the response suitable to the end user via the Provider mechanism.
>
> Consider this example. I have a method that returns an org.w3c.dom.Document instance, or perhaps an entity that is serializable as a jax-b XmlRootElement. A java client can consume it as is. However, for an end user over http I might need to represent it as xml for an ajax request, or perhaps perform an xsl or xquery transformation against it such that it is consumable by a web client. To achieve that I would need to:
>
> 1. Create a wrapper method that uses ResponseBuilder for most or all resource methods, or;
>
> 2. Create a provider that can perform the transformation generically.
>
> Since I want to leverage separation of the model and the view, and use jax-rs as the controller, I choose option 2, and delegate the view to the Provider. However, the Provider mechanism is too disconnected from the http request to complete the job. For instance, the request headers are unavailable to choose the correct encoding.

Providers support @Context injection so its easy to get the request headers in a MessageBodyWriter:

https://jsr311.dev.java.net/nonav/releases/1.0/spec/spec3.html#x3-520005

> One could implement MessageBodyReader to access them, but to no avail since a MessageBodyReader request cannot be tied to a MessageBodyWriter response.
>
> Next, to implement the view with a template-based model, an additional annotation would be needed. For example @Template( "User.xquery" ) or @Template( "User.xsl" ). A logical place for this template would be in the package of the resource method's enclosing class. Unfortunately, the MessageBodyWriter.writeTo method doesn't include type information for the enclosing class.

Its possible to get this information using an injected UriInfo (see #getMatchedResources) in the provider. The first entry in the returned list is the object that the request was dispatched to so you can get the corresponding class and then any annotations on it.

https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/UriInfo.html#getMatchedResources()

> The resource method and the enclosing resource class are joined, even for jax-rs internally; to wit, @Path, @Consumes, etc. Likewise for a Provider that needs to resolve package resources such as the template, or its imports. The absence of this forces the @Template author to require an additional property (for each method) as a package resource location such as @Template( value="User.xsl", resource="com.acme.Report" ).
>
> Annotations fail in the same way such that the MessageBodyWriter.writeTo method does not expose the annotations for the resource method's enclosing class. A Provider would likely seek to implement the same default annotations that jax-rs implementations make use of internally by annotating the resource class directly, and overriding at the method level as needed.
>
> CacheControl is another example that forces the application designer to make a hard choice. In my experience, cache control is typically a general policy that is overridden as needed. From what I can tell, in order to implement a rule of "Don't cache if it's dynamically generated" a choice must be made between using ResponseBuilder and a Provider, even for types that are otherwise natively supported by jax-rs. This is simple enough to solve if one is already implementing a provider. However, it "encourages" the author to choose the ResponseBuilder if they are not otherwise implementing a Provider.
>
Do you have in mind another way that such dynamic logic could be included without writing a provider or requiring a special method in the resource class ?

> I would recommend the specification be re-reviewed from the perspective that ResponseBuilder doesn't exist to ensure that jax-rs can meet the need without using it. In my opinion, ResponseBuilder is a "ch-easy" practice that has specific limited uses that should be discouraged as a "pattern." Don't get me wrong, I understand why it was necessary to include, which may be fine for anything other than an enterprise class entry.
>
> I mean this criticism for a good purpose. I believe this specification has the potential to cast aside all others in the web framework family. I look forward to it reaching a level of maturity that lures everyone away from the many frameworks (as it has lured me from my own).
>
Hopefully the above two clarifications get you what you need.

Thanks,
Marc.