users@jersey.java.net

[Jersey] Re: UriInfo injection at resource initialization time

From: Markus Karg <karg_at_quipsy.de>
Date: Wed, 9 Mar 2011 12:16:39 +0100

>UriInfo injection in constructor is used in an example in "Overview of
>JAX-RS 1.0 Features"
>http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features#OverviewofJAX-RS1.0Features->ConditionalGETsandReturning304%28NotModified%29Responses
>It also says "Notice that in this example the constructor of a
>resource class can be used perform actions that may otherwise have to
>be duplicated to invoked for each resource method".
>That makes perfect sense to me - but are you saying this wouldn't
>work in Jersey?
>I see a good specification/implementation letting me be flexible with
>my code, instead of making me bend my code to fit it.

Apparently it is not working in Jersey as you experienced and was explained already. See that this functionality is not mandatory by the JAX-RS 1.1 specification, so relying on that possibility would bind your code to a particular implementation, which is not what you want. If you need just a static URI, check Martin's solution. If you need a dynamic URI and do insist on getting it injected into the resource, you should file a RFE for the upcoming JAX-RS 2.0 standard, because in that case, JAX-RS 2.0 must forbid singletons (with all the negative side effects then).

>I had implemented the same functionality with a simple HttpServlet, so
>I'm still not sure if the transition to JAX-RS is worth the trouble.

JAX-RS is not in contrast to servlets. Servlets are for doing anything you like with http. JAX-RS is for doing explicitly REST. If you need REST, you're possibly better off with JAX-RS. If you don't, then I do not see why you actually want to use JAX-RS.

>> What is the problem with injecting it at invocation? You could have a facade resource just creating instances of your resource, passing in @Context for example.
>That seems like a workaround, but I could give it a shot. Could you
>please give an example of what you have in mind?

Actually it is not a workaround but it is exactly how JAX-RS wants it to be like, since a directory is not a plain file and vice versa. It is a difference between a resource (= a directory containing files) and its content (= a plaint file). So it makes rather sense to have *two* resources:

http://localhost/files <-- The directory

http://localhost/files/123 <-- The file (can be sub directory)

"Directory" Resource contains Individuals:

@GET @Path("individuals/{id}")
public Individual getIndividual(@Context UriInfo uriInfo) {
  return new Individual(uriInfo);
}

"File" ("Subdirectory") Resource implements Individual:

@GET
public ChildOfIndividual() {
  return new ChildOfIndividual();
}

I do neither see that this looks like a workaround nor being in any case uncommon in the sense of OOP. See that one is plural (@Path("individuals")), while the other is singular (implements Individual), so it obviously are two different things.

>> It is possible to make your resource implement your Individual interface, but you have to take care about the process >>sequence at runtime: You have no guarantee *when* the constructor of the resource is invoked, as the JAX-RS spec allows >>providers to use different custom life cycles. So it is valid in JAX-RS that your constructor receives null for @Context >>since it might be bound to e. g. @Path("/path") while it got invoked due to a request upon /path/123. If the resource got >>created per application (as per JAX-RS spec's default), obviously it wouldn't "see" the trailing "123" (as it was created >>already at that point in time). But it will "see" trailing "123" for the field injection, since that happens not at resource >>creation but at actual invocation. That explains the behaviour you have seen. There is no pure JAX-RS way to overcome that.
>Well then JAX-RS doesn't make much sense to me in this case... I think
>if Resource has a static URI like "/path" (which probably means it is
>a singleton of a root class) then it should be able to access it at
>any time (its own URI, not the request URI).

You can access the static path, just check Martin's mail to get the code line.

Regards
Markus

> -----Original Message-----
> From: Martynas Jusevicius [mailto:martynas.jusevicius_at_gmail.com]
> Sent: Mittwoch, 9. März 2011 10:16
> To: users_at_jersey.java.net
> Cc: Markus Karg
> Subject: Re: [Jersey] Re: UriInfo injection at resource initialization time
>
> Hey Markus,
>
> what if I want getIndividual() as a simple getter, not a resource method?
>
> It's not that Resource returns or contains Individuals, in essence
> Resource *is* (or could be) an Individual as well -- both REST and RDF
> object, since they share the same URI.
> I was thinking about making Resource implement Individual interface
> using the individual field, but that means it should be instantiated
> at (or right after) construction time - and I couldn't find a JAX-RS
> solution to that yet. Does that make sense?
>
> I can look up Individual using Resource URI - but has to be not null
> at that time.
>
> Martynas
>
> On Wed, Mar 9, 2011 at 8:21 AM, Markus Karg <karg_at_quipsy.de> wrote:
>> Try this one:
>>
>> @GET
>> @Path("individuals")
>> public Individual getIndividual(@Context UriInfo uriInfo) {
>>        return new Individual(uriInfo);
>> }
>>
>> Regards
>> Markus
>>
>> -----Original Message-----
>> From: Martynas Jusevicius [mailto:martynas.jusevicius_at_gmail.com]
>> Sent: Mittwoch, 9. März 2011 02:40
>> To: users_at_jersey.java.net
>> Subject: [Jersey] UriInfo injection at resource initialization time
>>
>> Hey list,
>>
>> I'm new here and would like to start with a question :)
>>
>> I have Resource classes implementing JAX-RS, however I also want to
>> combine it with RDF using Jena API.
>> Each Resource should have a reference to Individual (RDF resource) -
>> and they share the same absolute URI.
>> This is a root Resource class:
>>
>> @Path("")
>> @Singleton
>> public class TestResource
>> {
>>  private Individual individual = null;
>>
>>  ...
>> }
>>
>> This means Individual has to be initiated at some point, and at that
>> point the Resource needs to know its URI to be able to look up
>> Individual in the RDF model.
>>
>> What I've tried (the code goes inside the TestResource defined above):
>>
>> 1. Injected class field
>>
>>    @Context UriInfo uriInfo;
>>
>>    public TestResource()
>>    {
>>        System.out.println("TestResource.uriInfo: " + uriInfo);
>>    }
>>
>> Doesn't work - returns null
>>
>> 2. Injected constructor parameter
>>
>>    public TestResource(@Context UriInfo uriInfo)
>>    {
>>        System.out.println("TestResource(uriInfo): " + uriInfo);
>>    }
>>
>> Doesn't work - I get
>> java.lang.IllegalStateException
>>        com.sun.jersey.server.impl.ThreadLocalHttpContext.getUriInfo
>> as described in
>> http://jersey.576304.n2.nabble.com/injecting-UriInfo-in-constructor-td4510740.html
>> Same message suggests "access the reference when a request is in
>> scope" -- but this is not good enough.
>>
>> However constructor param is used in JAX-RS tutorial:
>> http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features#OverviewofJAX-RS1.0Features-ConditionalGETsandReturning304%28NotModified%29Responses
>>
>> 3. @PostConstruct method
>>
>>    @PostConstruct
>>    public void init()
>>    {
>>        System.out.println("@PostConstruct UriInfo: " + uriInfo);
>>    }
>>
>> Doesn't work - never gets executed
>>
>> Am I missing something? It seems as such a common use case - why isn't
>> there a simple solution?
>> I see no reason why root Resources with static @Path could not have
>> access to their UriInfo at any time - their URI is known right from
>> the start?
>> And why does @PostConstruct not work? I'm running Tomcat 6.0.26.
>>
>> Thanks,
>>
>> Martynas
>> semantic-web.dk
>>
>