users@jersey.java.net

Re: [Jersey] GuiceComponentProviderFactory.isInjectPresent only looks at constructors

From: Zach Cox <zcox522_at_gmail.com>
Date: Fri, 15 May 2009 10:58:52 -0400

> There are some docs on the package of the servlet:
>
> https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/contribs/jersey-guice/com/sun/jersey/guice/spi/container/servlet/package-summary.html
>
> but i think we need some on the GuiceComponentProviderFactory as well.

Ahhh now I see - the @Inject constructor thing is explained in the
numbered list at the bottom of that page. Yeah might be worth making
that more explicit in GuiceComponentProviderFactory.

> I am guessing you are not explicitly binding your classes in a module,
> correct?

Right - I'm not explicitly registering any of my root resource classes
that need Guice injection, I'm just doing this in my
configureServlets() override so Jersey will automatically find them
all:

serve("/*").with(GuiceContainer.class, params);

Although it looks like if I had explicitly done
bind(BlahResource.class) before serve("/*") then it would have had
method injection performed without defining any constructor injection,
is that correct?

> I just made a change in the trunk so you can override the functionality.  I
> renamed the method "isInjectPresent" to "isImplicitGuiceComponent" and you
> can override to modify what is considered to be an implicit Guice component.

Sounds great!

Thanks,
Zach


>
> Paul.
>
> On May 15, 2009, at 3:53 PM, Zach Cox wrote:
>
>>>> Is there a specific reason that
>>>> GuiceComponentProviderFactory.isInjectPresent only looks for Guice's
>>>> @Inject annotation on constructors?
>>>
>>> I thought that was the easiest solution for the case when Guice
>>> instantiates
>>> but Jersey manages the life-cycle. To enable such support you have to
>>> annotate a constructor with @Inject, and of course the class must not be
>>> explicitly bound. Do you think we should loosen such requirements to
>>> detect
>>> such cases?
>>
>> I originally had a case like this:
>>
>> public abstract class AbstractResource
>> {
>>  private Something something;
>>
>>  @Inject
>>  public void setSomething(Something something)
>>  {
>>   this.something = something;
>>  }
>>
>>  protected void doThing()
>>  {
>>   //do some stuff using the something object...
>>  }
>> }
>>
>> @Path("/blah")
>> public class BlahResource extends AbstractResource
>> {
>>  @GET
>>  public String get()
>>  {
>>   doThing();
>>   return "whatever";
>>  }
>> }
>>
>> So an abstract base resource class with a doThing() method that can be
>> reused by any resource class that extends the base.  doThing() needs a
>> Something object which Guice injects.  The best way to get Guice to
>> inject dependencies into an abstract base class seems to be to use
>> method injection (otherwise you end up with every subclass getting
>> deps injected into their constructors and calling the same super
>> constructor).
>>
>> Originally the Something was not being injected since BlahResource
>> defines no constructor injection.  I've actually refactored into
>> something more like this now:
>>
>> public interface Thing
>> {
>>  public void doThing();
>> }
>>
>> @Path("/blah")
>> public class BlahResource
>> {
>>  private Thing thing;
>>
>>  @Inject
>>  public BlahResource(Thing thing)
>>  {
>>   this.thing = thing;
>>  }
>>
>>  @GET
>>  public String get()
>>  {
>>   thing.doThing();
>>   return "whatever";
>>  }
>> }
>>
>> So I still get reusable doThing() behavior by injecting Thing
>> instances into resource class constructors (plus I can mock them out
>> in unit tests too).  I think this is a better design than the abstract
>> base resource class approach, but it still might be useful to at least
>> support method injection on resource classes, if not field injection
>> as well.  Constructor, Method, and Field all extend AccessibleObject
>> which defines the isAnnotationPresent method that isInjectPresent
>> uses, so it should be able to easily support method & field injection
>> too.
>>
>> Better yet, maybe isInjectPresent should be protected so we can
>> override & customize its behavior as necessary?  At the minimum,
>> GuiceComponentProviderFactory needs some javadocs that specify "Guice
>> will only inject dependencies into your resource class if it defines
>> constructor injection".
>>
>> Thanks,
>> Zach
>>
>>
>>> For explicitly bound classes the
>>> GuiceComponentProviderFactory.isInjectPresent is never utilized and there
>>> are no restrictions imposed by Jersey on what should be annotated.
>>>
>>> Paul.
>>>
>>>
>>>>  Guice also supports method and
>>>> field injection.  By not looking for @Inject on methods and fields,
>>>> resource classes that use method or field injection but not
>>>> constructor injection are not handled by Guice at all.
>>>>
>>>> Thanks,
>>>> Zach
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>
>