users@jersey.java.net

Re: [Jersey] Newbie question: How do I inject objects into resources

From: David Fogel <carrotsalad_at_gmail.com>
Date: Tue, 24 Mar 2009 19:32:37 -0400

Hi Ian, Paul, etc

I've been struggling with the same basic confusion as expressed by Ian
Clarke, and at first was delighted to find that this thread from
yesterday/today had so many responses.

But after reading the responses, I find I'm still confused, and maybe
a little alarmed at the implications this has for jax-rs interop.

So, I start with the same basic question:

Given that any non-trivial task involving writing a web app or service
will almost certainly necessitate connecting JAX-RS-style resource
classes with various data sources, back-end services,etc, what is the
recommended _JAX-RS_ feature that enables this?

I read through the JSR-311 spec fairly carefully, but it was strangely
silent on the topic, aside from mentioning the possibility of creating
custom ContextResolvers. My reading of the spec suggested to me that
I should create custom ContextResolvers for each object I wished to
have JAX-RS provide my resource classes, via @Context annotations on
method parameters or fields. For example, if I have an application
service called BackendService:

@Provider
public class BackendServiceResolver implements ContextResolver<BackendService> {
  private BackendService service;
  public BackendServiceResolver(BackendService service) {this.service
= service;}
  public BackendService getContext(Class<?> type) {
    return service;
  }
}

and then I could have a resource class like this:

@Path("/path")
public class MyResource {

  private BackendService service;

  public MyResource(@Context BackendService service) {
    this.service = service;
  }

  @GET
  public String getSomething() {
    return service.doSomething();
  }
}

But this doesn't work. Elsewhere on this list, from february I think,
Paul says that this isn't the correct use of custom ContextResolvers
(he says: "ContextResolver is not a way to provide generic injection
support as
is the case with InjectableProvider.") but to get it to work one has
to write the resource class like this:

@Path("/path")
public class MyResource {

  private BackendService service;

  public MyResource(@Context ContextResolver<BackendService> resolver) {
    this.service = resolver.getContext(null);
  }
  ....
}

In addition to being awkward, this also differs from how the JSR-311
spec describes accessing other _optional_ context items, such as
ServletContext, where the form is

public void someResourceMethod(@Context ServletContext sc) {...}

and not:

public void someResourceMethod(@Context
ContextResolver<ServletContext> resolver) {...}

Okay, so maybe my reading of the JAX-RS spec was wrong- what, then, is
the preferred way? The suggestions so far from the mailing list have
been things like:

suggestion A:
Use a custom InjectableProvider instead of ContextResolver

But InjectableProvider is a _Jersey_ class, not a JAX-RS class! Doing
this means that my code will be Jersey-specific, so I wouldn't be able
to run my restful service in a different container.

suggestion B:
Put your app services into the attributes inside a ServletContext or
ServletConfig, and access those things using the method above (public
void someResourceMethod(@Context ServletContext sc) {...})

But, in addition to being kind of a hack, I may not be in a servlet
context at all- the JAX-RS spec doesn't presume deployment in a
servlet container, and these Context items are optional. In
particular, I happen to be using an OSGi container.

suggestion C:
Use an external IoC/dependeny injection framework

But, isn't JAX-RS itself a dependency injection tool, albeit not a
general-purpose one? Wouldn't using non-spec features of a jax-rs
implementation like jersey, combined with some other IoC library like
Spring or Guice, mean that, like above, one's code would be
irrevocably tied to a particular toolset, and not portable at all? It
really sounds like people are effectively saying "Oh yeah, by the way,
no-one actually uses JAX-RS by itself, or even Jersey by itself, you
gotta use it through all these other layers, isn't that obvious?".

Even if that were a desirable thing, it's certainly not _obvious_, or
even particularly easy to figure out, when all the examples in the
spec, in Jersey sample code, and in introductory articles all over the
web show only JAX-RS API usage, and conveniently omit any mention of
this code actually needing to access anything useful.

I would really appreciate it if someone could provide a sort of
"here's the deal" explanation that addresses what role JAX-RS has as a
standard/spec in a technology toolset, with consideration given to the
concerns I've mentioned above regarding code portability, etc.

Thanks,
  -Dave Fogel