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