users@jersey.java.net

[Jersey] Re: UriInfo injection at resource initialization time

From: Martynas Jusevicius <martynas.jusevicius_at_gmail.com>
Date: Wed, 9 Mar 2011 15:14:22 +0100

Omg it works! By printing out the URI at least.

But don't you agree these resources should be @Singleton in principle?
What about Application.getSingletons() - is including resource
instance there the same as declaring it @Singleton? But anyway I don't
see how I could pass UriInfo to obtain TestResource instance to be
included there.

I had achieved the same using abstract Resource superclass (like in my
last example) with
- getPath() and getAbsolutePath() equivalents
- constructor Resource(Resource parent) - effectively building a
parent/child tree of Resource instances
- Servlet-like doGet(), doPost() etc methods
and the real HttpServlet mapping request URIs to Resource instances
and executing the appropriate do..() methods.

Martynas

On Wed, Mar 9, 2011 at 2:46 PM, Martin Matula <martin.matula_at_oracle.com> wrote:
> Hi,
> I think all you need to do is remove the singleton annotation and let
> Ontology.get() handle the performance optimizations (i.e. if a new instance
> of an individual is returned, or instances are cached).
> Martin
>
> On 9.3.2011 14:29, Martynas Jusevicius wrote:
>>
>> Markus&  Martin,
>>
>> thanks for your help, but although I thought I was getting somewhere,
>> now I can see that I'm still not...
>>
>> First of all, let me clarify -- in RDF environment there are no
>> "Directory" or "File" Resources. *All* Resources (basically anything
>> that has a URI) are/can have Individual and therefore must follow the
>> same interface, and this is easiest achieved by introducing an
>> abstract superclass which deals with the Individual interface.
>> Some of these Resources are singletons in the REST sense, some of them
>> not.
>>
>> Let me give a simplified example - in this case Individual is not
>> implemented (it contains a lot of methods) but simply contained by the
>> superclass:
>>
>> abstract public class Resource // implements Individual
>> {
>>     private Individual individual = null;
>>
>>     public Resource(UriInfo uriInfo)
>>     {
>>        System.out.println(uriInfo.getAbsolutePath().toString());
>>        // possible Individual initialization
>>        //setIndividual(Ontology.get(uriInfo.getAbsolutePath());
>>     }
>>
>>     public Individual getIndividual()
>>     {
>>        return individual;
>>     }
>>
>>     private void setIndividual(Individual individual)
>>     {
>>        this.individual = individual;
>>     }
>> }
>>
>> Individual has to be instantiated using Resource's absolute URI at
>> some point, ideally in the superclass constructor.
>>
>> Then, there is root TestResource at @Path("") and subresource
>> TestSubResource at @Path("sub").
>> Both of them should be singletons, since their path never changes and
>> only one instance is needed.
>>
>> @Path(TestRootResource.PATH)
>> @Singleton
>> public class TestRootResource extends Resource
>> {
>>     public static final String PATH = "";
>>
>>     public TestRootResource(@Context UriInfo uriInfo)
>>     {
>>        super(uriInfo);
>>     }
>>
>>     @GET
>>     @Produces("text/plain")
>>     public String doGet()
>>     {
>>        return "TestResource.doGet()";
>>     }
>>
>>     @Path(TestSubResource.PATH)
>>     public TestSubResource getSubResource(@Context UriInfo uriInfo)
>>     {
>>        return new TestSubResource(uriInfo);
>>     }
>> }
>>
>> @Singleton
>> public class TestSubResource extends Resource
>> {
>>     public static final String PATH = "sub";
>>
>>     TestSubResource(UriInfo uriInfo)
>>     {
>>        super(uriInfo);
>>     }
>>
>>     @GET
>>     @Produces("text/plain")
>>     public String doGet()
>>     {
>>        return "TestSubResource.doGet()";
>>     }
>> }
>>
>> This is probably closest to what I'd like to achieve, and doesn't seem
>> that different from Martin's example - but of course it doesn't work
>> since I get the aforementioned IllegalStateException.
>>
>> UriBuilder usage like fromResource(TestSubResource.class).build()
>> gives me nothing new here, since I just as well can use
>> TestSubResource.PATH.
>>
>> The example seems JAX-RS compliant to me, but can you suggest how this
>> can be refactored to work with Jersey?
>> Most importantly, how and where can the absolute URI be extracted and
>> used to initialize Individual?
>>
>> Thanks again,
>>
>> Martynas
>> semantic-web.dk
>>
>> On Wed, Mar 9, 2011 at 12:16 PM, Markus Karg<karg_at_quipsy.de>  wrote:
>>>>
>>>> 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
>>>>>
>