users@jersey.java.net

Re: Guice integration in 0.6

From: Richard Wallace <rwallace_at_thewallacepack.net>
Date: Sat, 01 Mar 2008 01:28:35 -0800

Paul Sandoz wrote:
>
> On Feb 29, 2008, at 6:51 PM, Richard Wallace wrote:
>
>> Hello,
>>
>> I just updated to Jersey 0.6 and have a few thanks/gripes/questions.
>>
>> First of all, good job on getting rid of the requirement to put
>> services in the
>> META-INF/services/whatever.service.interface.your.implementing. Much
>> better.
>>
>> Now for the gripe. I love that the ComponentProvider is responsible
>> for instantiating everything, including MessageBodyReaders/Writers.
>> The problem I have now is that my preferred method of injection is
>> via constructors, but this causes Jersey to try and figure out what
>> to inject and call the getInstance() method that takes a constructor
>> and it's (resolved by Jersey) parameters. So what I've wound up
>> having to do is toss the constructor and parameters in my
>> GuiceComponentProvider and just return
>> injector.getInstance(ctor.getDefiningClass()). Of course that means
>> that Jersey params can't be injected into the constructor which leads
>> to my question...
>>
>
> This area of constructors and who chooses what is a tricky area we
> have not quite fully resolved. For portability we do require a rule
> for which constructor is used. Jersey does a fair bit of work to get
> the instances of the constructor parameters e.g. @*Param
> (@QueryParam("q") List<Integer> v, or @DefaultValue("10")
> @QueryParam("q") BigInteger v) in addition to @Context stuff that
> would be a fair bit of work to implement.
>
> Perhaps an example in Guice would help me as i don't understand when
> you say "my preferred method of injection is via constructors" why you
> cannot use the constructor Jersey chooses. Is it because Guice gets to
> decide which constructor to use?
>

The most common scenario is something like below:

@Path("/items/{item-name}")
public class ItemResource {

    private final ItemRepository repository;

    @Inject
    public ItemResource(ItemRepository repository) {
        this.repository = repository;
    }

    ...
}

So when Guice gets a request to create an instance of ItemResource it
will find the constructor annotated with the @Inject annotation and use
that passing it the required dependencies. In a case like the above, it
would be nice to be able to add the UriInfo object and probably the
item-name parameter since that is going to be something needed by all
the methods. Up until now I've simply been having that stuff passed to
the methods as parameters which is ok, but doesn't seem quite as nice.

The way I would go about binding those parameters in Guice is along the
lines of something like this:

public class JerseyModule extends AbstractModule {

    public void configure() {
        bind(UriInfo.class).annotatedWith(Context.class).toProvider(new
Provider() {
            // lookup thread local context or the thread local UriInfo
and return it
        });
    }
}

That's just for the UriInfo type. I'd also need to create bindings for
the other possible values as well. Since the ThreadLocalHttpContext is
something internal to the Jersey implementation it seems it would be
better if I could have some better way of looking these things up, but
I'd settle for getting that much at this point.

>
>> I'd like to be able to have Guice inject JSR311 parameters, like
>> @Context and @HttpHeaders and such. I'm pretty sure I can do it,
>> it's actually quite easy with Guice I just need to implement the
>> providers. The providers will just return the ThreadLocals that
>> Jersey uses. The problem I have is that I have no access to those
>> ThreadLocals. They're all declared as private in the
>> WebApplicationImpl and their is no API to access them from
>> ComponentProviders. From what I can tell, all I really need is
>> access to the ThreadLocalHttpContext and from there I should be able
>> to get everything I need for injection. Is that correct? How can I
>> get access to this ThreadLocal?
>>
>
> I could add a method WebApplication.getThreadLocalHttpContext() but
> first i would like to understand more about the issue. It may be we
> need something like "given a list of types, from say a constructor,
> get me the instances of those types Jersey knows about in the context
> of the current request" then you would have not to re-implement a
> whole bunch of logic.
>
>
>> Thanks,
>> Rich
>>
>> P.S. One more gripe for the road. I've had to add
>> @SuppressWarnings("unchecked") annotations to my
>> GuiceComponentProvider for the getInstance() methods because they're
>> not generified. Could we get this fixed? I mean, all that needs to
>> be done is to do something like declare them as
>>
>> <T> T getInstance(Scope scope, Class<T> type)
>>
>> and
>>
>> <T> T getInstance(Scope scope, Constructor<T> ctor, Object[] args)
>>
>
> I will make that change on Monday.
>
>
>> I've noticed in going through the code that there are many other
>> places where raw types are used in Jersey instead of generified types.
>
> Could you point to other areas?
>

Well, there are quite a few of them, so I can't list them all out. ;)
Eclipse lists 255 over the entire project, with 39 in api, 198 in impl
and 18 in spi. The ones that would probably most effect people like me
are the ones in spi, but the ones in api are arguably just as important.

>
>> Any reason for this?
>>
>
> Most likely laziness on my part.
>
> Paul.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>