users@jersey.java.net

Re: Generating urls and controlling rendering/serialization

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 29 Feb 2008 11:41:55 +0100

Jo St?rset wrote:
> Hi,
>
> let me say I'm plesantly surprised by the quality and ease-of-use of
> jsr-311 and jersey, even at this early stage.

Thanks!


> However, there are a
> couple of things that bothers me, and I thought it might be a good idea
> to ask on this list (sorry for the long post :)
>

That is OK, i really appreciate the time you have taken.


> 1) Controlling rendering/serialization
>
> I like the idea of just returning domain "model" objects from resource
> objects, and let a seperate "view layer" in the framework resolve and
> generate the view. This works pretty well with jaxb and xml
> out-of-the-box, so with just a little bit more ability to control this i
> would be well underway to have everything I need for my app.
>
> I've tried to make a freemarker template processor modeled after the jsp
> variant, but it doesn't seem to get called as expected. Is this not
> supposed to work yet, or have I missed how I register this provider
> correctly. The documentation is a bit sparse, and the source code is a
> bit to complex for me to immediately figure out how things work :)
>

Yes, the docs are sparse :-( there could be some bugs as i have not
tried anything but JSP integration, and i just put back the feature and
it sort of requires developers to roll up their sleeves and get their
hands dirty, and ask me questions :-) and provide feedback to improve it.

How have you implemented the freemarker template processor? can you
provide some example code.

The runtime code loops through all registered template processors until
it finds one that returns a non-null value for the resolve method, see
the following code for:

    com.sun.ws.rest.impl.template.ViewableMessageBodyWriter#63

             for (TemplateProcessor t : tc.getTemplateProcessors()) {
                 String resolvedPath = t.resolve(absolutePath);
                 if (resolvedPath != null) {
                     resolved = true;
                     t.writeTo(resolvedPath, v.getModel(), entityStream);
                 }
             }

that processes Viewable instances returned by a resource.

The idea is that each template processor would key off a different
suffice, like ".jsp" for JSP templates or say "*.fm" for freemarker
templates.

So lets say we write a theoretical freemarker template:

   @Provider
   public class FMTemplateProcessor implements TemplateProcessor {
      public String resolve(String path) {
           if (!path.endsWith(".fm"))
               path = path + ".fm";

           ClassLoader cl = Thread.currentThread().
               getContextClassLoader();

           URL r = cl.getResource(path);
           if (r == null) return null;
           return r.toString();
       }
   }

So the resolve method would try and find freemarker templates as
resources in the classpath. Say for example we have this resource class:

   package foo;

   @Path("/foo")
   public class Foo {
      @GET public Viewable get() {
        return new Viewable("show", "model");
      }
   }

and there was a freemarker template placed in the classpath at the location:

   /foo/Foo/show.fm

then the runtime will call the FMTemplateProcessor.resolve with the value:

   /foo/Foo/show

and the resolve method should return something like:

   <scheme>:<path>/foo/Foo/show.fm


> Another thing I'd like is to be able to add a combination of xml
> serialization (jaxb) combined with an xsl transformation to be able to
> produce a html view. Would this be possible?
>

I think so, one could have an XLSTemplateProcessor that looks for ".xsl"
style sheets and can apply marshalled JAXB objects (as SAX events?) to them.


> As a third option, I'd like to add a simple processing instruction with
> an xsl reference to the resulting jaxb xml. I haven't found an elegant
> way to do this with jaxb, and I suspect I need to tweek the jaxb
> messagewriter or replace it with a custom handler. Any idea how i could
> do this elegantly?
>

Hmm... one way to do this is to write your own message body writer that
process a type:

    public class JAXBPIElement {
       Object getJAXBElement() { ... }
       String getPI() { ... }
    }

Off the top of my head the message body writer could be written as follows:

@Provider
public class JAXBPIElementWriter implements
     MessageBodyWriter<JAXBPIElement> {

   boolean isWriteable(Class<?> type) {
       return JAXBPIElement.class == type;
   }

   void writeTo(JAXBPIElement t, MediaType mediaType,
       MultivaluedMap<String, Object> httpHeaders,
       OutputStream entityStream) throws IOException {

       Object o = t.getJAXBElement();
       // Check if annotated with @XMLElement

       PrintStream ps = new PrintStream(entityStream);
       ps.println("<?xml version='1.0'?>");
       ps.println(t.getPI());

       // Copy code from the following to get the JAXBContext
       // com.sun.ws.rest.impl.provider.entity.XMLJAXBElementProvider
       JAXBContext context = ...
       Marshaller m = context.createMarshaller();
       m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
       m.marshal(poe,ps);
   }
}

I don't know any other way than tweaking the marshaling.

Paul.

> 2) Generating urls
>
> I have seen some this discussion of this before, but haven't really
> found any good recommendations to this important topic. So I give it
> another go :)
>
> What makes rest work is the interlinking of resource representations, so
> it's fairly important for links to other representations to be present
> in representations. Given that I want to mainly avoid custom generation
> of the representations in the resources themselves (se 1), this seems
> like the biggest problem I have with the jsr-311 approach.
>
> For now I have done a hack by adding a url bean property to my domain
> objects (the ones that represent rest resources), and on my @GET methods
> I explicitly write this property before returning the object (for jaxb
> serializing). Is there any way to avoid this?
>
> In addition to requiring my domain objects to have this property (which
> really isn't nice), there's a couple of additional things that bothers me.
>
> The first problem I have is the fact that every resource needs to
> explicitly know how to generate urls to every other resource(type) that
> is to be linked in the representation. This leads to *a lot* of
> duplication, and I don't like a so central part of a rest based
> application to lead to such an amount of manual and error prone
> duplication.
>
> Maybe I haven't understood the model good enough, but the second problem
> I have is that the jsr-311 model seems to dictate a duplication of the
> domain model in a seperate resource layer on top. All my resource
> objects need to know the mapping between the domain objects and the
> correponding resource objects containing the annotation mapping (and
> usually som hard coded path attibutes as well) for every link it is to
> generate.
>
> In reality I end up with hard coded duplication of the annotation based
> request mapping everywhere I want to represent hyper links. Since almost
> all the necessary information to be able to create links has been added
> to the application through the jsr-311 annotations, this really doesn't
> feel right. Can anyone enlighten me, I'm kind hoping that I have
> misunderstood something fundamental here :)
>
> Do you have any suggestions for how to do this in a better way?
>
> Jo
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>

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