users@jersey.java.net

AW: AW: AW: [Jersey] Reverse Lookup

From: Lerenc, Vedran <vedran.lerenc_at_sap.com>
Date: Tue, 1 Jun 2010 04:35:30 +0200

Hi Paul,

thank you for the hints! However, I am not sure whether a filter will help me. Is a filter - as described in the JavaDoc - called before a request/after a response? In my case the system may get a PUT before a GET (let's say the system was restarted and some application which did a GET a long time ago, now comes with a PUT). As long as I don't persistent the proposed map of yours (which I also can generate directly when I serve my resources in the GETs), I have never seen resources of this type in a filter after the restart - yet I have to map them.

Is there something else (like a registry) in Jersey that gives me all RootResources back? Or is a filter what I look for? However, when I implement a com.sun.jersey.spi.container.ResourceFilter which I register with com.sun.jersey.spi.container.ResourceFilters I should implement two methods called getRequestFilter() and getResponseFilter(), which don't sound like they would help me, because I shall return com.sun.jersey.spi.container. ContainerRequestFilter/ ContainerResponseFilter instances which react only on requests/responses. In my case a get a PUT on one resource type with some URIs that I created with UriBuilder of a totally different resource type (either just a few milliseconds before or weeks before), i.e. the resource type in question (the contained one) didn't run through these filters, might even never been served through Jersey. It was annotated with @Path and at least once I called the UriBuilder to get the path, but that might have happened a long time ago.

As a side note: In fact I had (and have) similar issues with XStream that doesn't know about XStreamAlias annotated resources until it serializes them for the first time (you have no problems without XStreamAlias, as then XStream runs its default class mapping which takes the full class name), i.e. if a PUT hit me before a GET, it failed until I implemented a very ugly workaround for the time being: some ugly name guessing and package prefixing, but it feels so wrong. If only I could get a hand on what Jersey knows, i.e. on all resources types, then I could solve my problems. I just don't want to do the work twice and annotate resources AND put them also in a map of mine - if possible at all. If not, I will do that (fill and keep my own map manually) as my XStream hack is inacceptable, too. The filters, as I understood them, showed me no way out, but I may be wrong about them.

Regards,

Vedran



Von: Paul.Sandoz_at_Sun.COM [mailto:Paul.Sandoz_at_Sun.COM]
Gesendet: Montag, 31. Mai 2010 11:03
An: Lerenc, Vedran
Cc: users_at_jersey.dev.java.net
Betreff: Re: AW: AW: [Jersey] Reverse Lookup

On May 30, 2010, at 2:15 PM, Lerenc, Vedran wrote:
Hi Paul,

> What the issue is about is essentially a reverse operation. We need to match the path to a resource class...

Yes, that's what I am looking for.

> In the interim of any such functionality

Oh, I am surprised as I thought it is good REST style to use URIs where the resources shouldn't go over the wire.

Yes, URIs in the representations.



Hence, if I am supposed to do that, I need a way back from the URI to my object. I don't want to add redundant code - I have used the PATH annotation, use already the UriBuilder to map resources to URIs and hoped for a clean way back, thereby minimizing redundancy and bugs in my code (an own little mapper might get out of sync with the @PATH annotations if other developers take over/join team).

A valid point. JAX-RS 1.x punted better support for linking and hypermedia to a JAX-RS 2.0 effort.




> i can provide details of a way of obtaining the URI templates for the set root resources (and templates for sub-resource locators and sub-resource methods), and from that you can concoct your own reverse matching. I can send more details as required.

That would be great! Yes, please send me some information so that I can do the reverse mapping. Thanks in advance!


OK. In the interim of fixing this here are some guidelines.

You can register a ResourceFilterFactory:

  https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/container/filter/package-summary.html

that does not add any filters but just analyses each AbstractMethod of a resource class. From the AbstractMethod instance you can get access to the AbstractResource as well. Anything with an @Path on it implements PathAnnotated:

  https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/api/model/PathAnnotated.html

from which you can get the path value.

  UriTemplate t = new PathTemplate(a.getPath().getValue());
  PathPattern p = new PathPattern(t);

So you can obtain all the path patterns for all root resources and add them to a sorted map (or set).

  public class MyMap<R> extends TreeMap<PathPattern, R>{
      public MyMap() {
          super(PathPattern.COMPARATOR);
      }
  }

and then you can linearly match each PathPattern using PathPattern.match.

Note that because of the JAX-RS matching algorithm you cannot merge path patterns at multiple levels (e.g. @Path on root resource classes and @Path on methods of those classes) as this will result in incorrect matching depending on the @Path values. So as you can guess it can quickly get more complex.


To fix this issue what i need to do is provide a set of "uri rules" for reverse look up. Jersey has already has a set of rules for matching, but i would prefer to keep the reverse look up functionality separate so that it can be optimized (e.g. one does not require to create an internal request context if a resource class is matched but the instance is not required).

Paul.