users@jersey.java.net

Re: Returning a class from a sub-locator

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 19 Feb 2008 15:32:52 +0100

Hi Martin,

Martin Grotzke wrote:
> being able to return a class sounds really great!
>
> Though, in our case we have something like a resource (Items) with path
> "/items" and another resource (Item) with path "{itemId}". In the Item
> resource we need access to the path parameter "itemId".
>

See end of email for an example taken from the unit tests, you can use
@PathParam, but it does require that the class returned is implicitly
aware of the template name "itemId" used by the parent.

This is why i think it would also be nice to use the ComponentProvider
iface to pass in the constructor parameters for per-request life-cycle
resources. For example:

         @Context ComponentProvider cp;

         @Path("{itemId}")
         public Class<?> getItem(@PathParam("itemId") String id) {
             Object[] params = new Object[1];
             params[0] = id;
             return cp.getInstance(ItemResource.class, params);
             // Hmmm should change Object[] params to Object... params
             // then it could be:
             // return cp.getInstance(ItemResource.class, id);
         }

or:

         @Context ComponentProvider cp;

         @Path("{itemId}")
         public Class<?> getItem(@PathParam("itemId") String id) {
             Object r = new ItemResource(id);
             cp.inject(r);
             return r;
         }


> Is there any way to retrieve the value of "itemId" within Item if it is
> instantiated by an ioc-container like spring?
>

Yes, as shown below.


> Btw: I'm just starting with jsr311/jersey and like it very much -
> congrats and thx a lot!
>

Thanks for the kind words,
Paul.

     @Path("/{p}")
     static public class ParentWithTemplatesLifecycle {
         @GET
         public String getMe(@PathParam("p") String p) {
             return p;
         }

         @Path("child/{c}")
         public Class<ChildWithTemplatesPerRequest>
getChildWithTemplates() {
             return ChildWithTemplatesPerRequest.class;
         }

         @Path("child/singleton/{c}")
         public Class<ChildWithTemplatesSingleton>
getChildWithTemplatesSingleton() {
             return ChildWithTemplatesSingleton.class;
         }
     }

     static public class ChildWithTemplatesPerRequest {
         private int i = 0;
         private String c;

         public ChildWithTemplatesPerRequest(@PathParam("c") String c) {
             this.c = c;
         }

         @GET
         public String getMe() {
             i++;
             return c + i;
         }
     }

     @Singleton
     static public class ChildWithTemplatesSingleton {
         private int i = 0;

         @GET
         public String getMe(@PathParam("c") String c) {
             i++;
             return c + i;
         }
     }


>
> On Tue, 2008-02-19 at 12:24 +0100, Paul Sandoz wrote:
>> Hi,
>>
>> One of the major pain points i have observed from developers is that
>> sub-locators return objects and it is necessary to manually pass
>> contextual information injected on the root resource classes to
>> resources instantiated and returned by sub-locators.
>>
>> I have modified things in the trunk so that it is possible for a
>> sub-locator to return a Class. For example:
>>
>> @Path("/parent")
>> static public class Parent {
>> @GET
>> public String getMe() {
>> return "parent";
>> }
>>
>> @Path("child")
>> public Class<Child> getChild() {
>> return Child.class;
>> }
>> }
>>
>> static public class Child {
>> @GET
>> public String getMe() {
>> return "child";
>> }
>> }
>>
>> The standard life-cycle mechanisms (singleton or per-request) should all
>> work as before and Jersey will defer to a component provider for
>> instantiating the returned class. So it should be much easier to work
>> with Spring.
>>
>>
>> Another fix i am considering is allowing injection of ComponentProvider:
>>
>> @Path("/parent")
>> static public class Parent {
>> @Context ComponentProvider cp;
>>
>> @GET
>> public String getMe() {
>> return "parent";
>> }
>>
>> @Path("child")
>> public Child getChild() {
>> Child c = new Child();
>> // Spring does not support this :-(
>> cp.inject(c);
>> return c;
>> }
>> }
>>
>> @Path("/parent")
>> static public class Parent {
>> @Context ComponentProvider cp;
>>
>> @GET
>> public String getMe() {
>> return "parent";
>> }
>>
>> @Path("child")
>> public Child getChild() {
>> return cp.getInstance(c);
>> }
>> }
>>
>> which allows the application to have some extra control over the
>> instance before it is returned. Is this something people would find useful?
>>
>> Thanks,
>> Paul.
>>

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