users@jersey.java.net

Re: [Jersey] Jersey 1.1 and implicit views

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 15 Dec 2009 10:05:14 +0100

Hi Owen,

Implicit views, as named, are implicitly implemented by Jersey, thus
the only thing they can return as the model is the controller itself.

For implicit views to work in conjunction with resource methods views
you need to do something like the following:

@Path("/hello")
@ImplicitProduces("text/html;qs=5")
public class Hello {
         @GET
        @Produces("application/xml")
        public HelloDocument getXml() {
                return new HelloDocument();
        }
}

The view can then access the property "index" to obtain the
HelloDocument instance. Note the "qs" parameter on the
@ImplicitProduces value. The "qs" value is multiplied by the "q" value
in the accept header thus the server is biasing to return text/html
over application/xml.

See the bookstore sample for such cases:

   http://download.java.net/maven/2/com/sun/jersey/samples/bookstore/1.1.4.1/bookstore-1.1.4.1-project.zip


The following is almost equivalent to the above:

@Path("/hello")
public class Hello {
         @GET
        @Produces("text/html")
        public Viewable getIndex() {
                 return new Viewable("index.jsp", this);
        }

         @GET
        @Produces("application/xml")
        public HelloDocument getXml() {
                return new HelloDocument();
        }
}

But unfortunately "qs" parameters are not currently supported on
@Produces values. It is something i need to implement. Thus for some
browsers, like Safari, XML will be returned rather than HTML because
it is more preferable. The solution to this problem is to write a
filter to "normalize" the Accept header for browser-based user agents
such that text/html is always the most preferable.


> So here are my questions:
>
> 1. Is it possible to use implicit viewables and prioritize text/html
> instead of application/xml?

Yes, see above.


> 1b. Why did my first attempt produce HTML when I asked for XML, and
> how can I avoid that (and ideally produce 406 responses instead) in
> the future?

Because you did not annotate the method "getIndex" with @GET.


> 2. What's the rationale behind passing the JAX-RS resource instance
> to the JSP as "it" rather than the value returned from the request
> handler method?

The controller is the only thing that is consistently available to act
as the model. There is no way, currently, for the controller to tell
Jersey what the model should be for the set of implicit views (there
can be a number of implicit views associated with the controller,
where the name of the implicit view defines the path, with a special
case for "index").


> 3. Is it possible to configure Jersey to pass the resulting
> HelloDocument bean to the JSP as "it", instead of the Hello instance?

Yes, but you have to turn the implicit view into an explicit view. But
as a consequence you loose the prioritization feature and will need to
"normalize" the accept header.


We are currently gathering requirements/use-cases for the MVC area so
we can improve it. So your feedback is most helpful,
Paul.


On Dec 15, 2009, at 3:09 AM, Owen Jacobson wrote:

> Hi guys,
>
> I'm trying out Jersey, since a lot of JAX-RS makes good sense to me,
> and while I'm very happy with it as a way of producing APIs, I'm
> having trouble getting implicit views to work the way I think they
> should.
>
> First, some background: my philosophy on webapp development runs
> along the lines that the URLs for a given resource should be the
> same whether it's a user with a browser accessing it (and getting
> HTML back) or a program accessing it (and getting XML or JSON back).
> URL decorations like ".xml" vs ".html" extensions don't appeal to
> me. JAX-RS's content negotiation supports that really well, provided
> you're building HTML as a String or Reader somewhere for HTML views.
> Jersey's implicit viewables, from what I've read on this mailing
> list and on Paul Sandoz' blog, seem to do what I want using JSP as
> the view technology.
>
> So, with all of that said, here's what I've got. There are two
> classes: a JAX-RS resource class:
>
> package ca.grimoire.scratch.jersey;
>
> import javax.ws.rs.Path;
> import javax.ws.rs.Produces;
>
> import com.sun.jersey.api.view.ImplicitProduces;
>
> @Path("/hello")
> @ImplicitProduces("text/html")
> public class Hello {
> @Produces("application/xml")
> public HelloDocument getIndex() {
> return new HelloDocument();
> }
> }
>
> // EOF //
>
> and a JAXB-mapped bean class:
>
> package ca.grimoire.scratch.jersey;
>
> import javax.xml.bind.annotation.XmlElement;
> import javax.xml.bind.annotation.XmlRootElement;
>
> @XmlRootElement(name = "hello", namespace = "http://www.example.com/jersey-jsp-example
> ")
> public class HelloDocument {
> @XmlElement
> public String getMessage() {
> return "Hello, world!";
> }
>
> }
>
> // EOF //
>
> I've also got a template in ca/grimoire/scratch/jersey/Hello/
> index.jsp:
>
> <html>
> <head>
> <title>It works!</title>
> </head>
>
> <body>
> <h1>Message</h1>
> <p>${it.index.message}</p>
> </body>
> </html>
>
> Finally, for completeness, web.xml:
>
> <?xml version="1.0" encoding="UTF-8"?>
> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
> "
> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
> http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
> version="2.5">
> <servlet>
> <servlet-name>Jersey</servlet-name>
> <servlet-
> class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-
> class>
> <init-param>
> <param-name>com.sun.jersey.config.property.packages</
> param-name>
> <param-value>ca.grimoire.scratch.jersey</param-value>
> </init-param>
> <init-param>
> <param-
> name>com.sun.jersey.config.feature.ImplicitViewables</param-name>
> <param-value>true</param-value>
> </init-param>
> </servlet>
>
> <servlet-mapping>
> <servlet-name>Jersey</servlet-name>
> <url-pattern>/rs/*</url-pattern>
> </servlet-mapping>
> </web-app>
>
> I'm serving my app inside Jetty 7.0.1.v20091125 (via jetty-maven-
> plugin).
>
> Looking at https://jersey.dev.java.net/servlets/ReadMsg?listName=users&msgNo=4832
> suggests that this should produce HTML by preference, or XML when
> XML is requested. Unfortunately, that's not what I actually see:
>
> $ curl http://localhost:8080/rs/hello
> <html>
> <head>
> <title>It works!</title>
> </head>
>
> <body>
> <h1>Message</h1>
> <p>Hello, world!</p>
> </body>
> </html>
>
> (This is as desired.)
>
> $ curl --header 'Accept: application/xml' http://localhost:8080/rs/hello
> <html>
> <head>
> <title>It works!</title>
> </head>
>
> <body>
> <h1>Message</h1>
> <p>Hello, world!</p>
> </body>
> </html>
>
> (This is not, and a 406 NOT ACCEPTABLE would've been vastly
> preferable to the wrong content type.)
>
> I also get a WARNING in the logs:
> WARNING: A resource class, class ca.grimoire.scratch.jersey.Hello,
> does not have any resource method, sub-resource method, or sub-
> resource locator.
>
> Since none of the methods are annotated with @GET, this makes sense,
> but I can't figure out from the docs where @GET belongs in this case.
>
> Rewriting Hello without @ImplicitProduces but *with* a @GET, as
>
> package ca.grimoire.scratch.jersey;
>
> import javax.ws.rs.GET;
> import javax.ws.rs.Path;
> import javax.ws.rs.Produces;
>
> @Path("/hello")
> public class Hello {
> @GET
> @Produces("application/xml")
> public HelloDocument getIndex() {
> return new HelloDocument();
> }
> }
>
> does almost what I want -- provided the Accept header is specific
> enough. Browsers, or at least Safari, still get the "wrong" content
> type (application/xml, instead of text/html) by default, which makes
> actually using the application a little painful.
>
> It's also odd to me that the "it" attribute in the resulting page is
> the resource itself, rather than the bean returned from the resource
> method -- note that Hello#getIndex() returns a HelloDocument, which
> has a "message" bean property (getMessage() only), but the JSP uses $
> {it.index.message} and invokes Hello#getIndex().getMessage() rather
> than ${it.message} and HelloDocument#getMessage(), as I would've
> expected.
>
> So here are my questions:
>
> 1. Is it possible to use implicit viewables and prioritize text/html
> instead of application/xml?
> 1b. Why did my first attempt produce HTML when I asked for XML, and
> how can I avoid that (and ideally produce 406 responses instead) in
> the future?
> 2. What's the rationale behind passing the JAX-RS resource instance
> to the JSP as "it" rather than the value returned from the request
> handler method?
> 3. Is it possible to configure Jersey to pass the resulting
> HelloDocument bean to the JSP as "it", instead of the Hello instance?
>
> Cheers, and thanks for an otherwise awesome tool.
>
> -o
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>