users@jersey.java.net

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

From: Zach Cox <zcox522_at_gmail.com>
Date: Fri, 15 May 2009 09:53:04 -0400

>> 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
>
>