users@jersey.java.net

[Jersey] Re: UriInfo injection at resource initialization time

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

Martynas,

@Singleton's intention is to *guarantee* that there is only one instance at any time in case *you need* it (e. g. it *must* share the same values etc.). It is not something that you *can* set, but something that you *must* set. If you don't have a reason for, don't use it.

getSingletons() is used to get the *root* resources, which typically are singletons as they don't have a dynamic part in the ID. As soon as a dynamic part in the ID is needed, the common sense in JAX-RS is to use a sub-resource locator and return a dynamically created instance. Even if all that instances would be the same and *could* be singletons, there is no need to enforce singletons for sub-resources. It just makes things complex.

So you see, there *is* this directory-and-file pattern used here, even if you don't think thous would be natural -- it *is* natural in JAX-RS. The singleton root resource is always there, and works like a static directory root. Everything belong is created dynamically, even if it doesn't change at any time and *could* be a singleton, technically it *should not* be a singleton to keep things simple.

If you really need a singleton at that level, you must inject into a field.

Regards
Markus

-----Original Message-----
From: Martynas Jusevicius [mailto:martynas.jusevicius_at_gmail.com]
Sent: Mittwoch, 9. März 2011 16:00
To: users_at_jersey.java.net
Cc: Martin Matula
Subject: [Jersey] Re: UriInfo injection at resource initialization time

I'm not insisting, I'm saying that these Resources have the properties
of @Singletons - but apparently Jersey doesn't work that way. So from
my point of view there's something wrong with the implementation.

The second part of the email was an answer to your question "how did
you do it with HttpServlet?".

On Wed, Mar 9, 2011 at 3:54 PM, Martin Matula <martin.matula_at_oracle.com> wrote:
> Hi Martynas,
> If you insist on singletons, you can still do that if you initialize them
> lazily upon the first request, provided you are calling getIndividual()
> always in the context of a request.
> I don't understand the second part of your e-mail.
> Martin
>
> On 9.3.2011 15:14, Martynas Jusevicius wrote:
>>
>> 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
>>>>>>>
>