users@jersey.java.net

Re: [Jersey] injecting _at_Context fields on sub resources...

From: James Strachan <james.strachan_at_gmail.com>
Date: Mon, 2 Aug 2010 17:26:39 +0100

On 2 August 2010 16:11, Paul Sandoz <Paul.Sandoz_at_oracle.com> wrote:
> Hi James,
>
> AFIAK style A would enable a one-level deep relationship between a root
> resource and a sub-resource.

Sorry I wasn't very clear. For style A I was assuming we can add a sub
resource to any resource; whether its a root or sub resource.


> It would enable the developer to add
> sub-resources to a any root resource if that was intended or otherwise
> (although one could devise ways to disallow that).
>
> In such a case it would be almost as easy to make the sub-resource in style
> A a root resource with @Path("whatever/bar/{id}") if there is no value in
> the parent/sub relationship. Some shared behavior could be inherited from a
> common base class. The downside in this case is the "whatever" is repeated.

But imagine a deeply nested tree...

/customers/123/orders/abc/detail

where you've navigated through 4 resources. Then imagine the "detail"
resource having to basically copy-paste all of those URI templates and
handle all the path params then probably replicate much of the
functionality of those resource beans too.

But for a single sub resource when the parent root resource uses a
simple static uri template when there's not much injection going on
then you're right, style A only really helps for the injection of sub
resources.


> Do you envisage a use-case where a sub-resource is added to a root resource
> without modification to the latter? I guess that is what makes me
> uncomfortable about style A.

Yes. The idea is to add a sub resource to an existing resource (root
or sub or subsub etc), without having to change the entire tree of
resource beans or refactoring them all to shove in some injection
magic or provide a derived class for each resource etc.

If you own the source code and can add a compile time dependency on
the new sub resource then style C is an alternative too. Though I
prefer style A as its more DRY and lets JAXRS web applications be more
easily extensible. Each web application has an explicit set of
packages searched; but I can put the same base web app into different
builds which include new additional sub-resources with style C.


> I suppose in Guice one could could modify the bindings such that BarResource
> is bound to a specialized implementation, in fact one might qualify it in
> this case so BarResource is reusable in other contexts:
>
> @Path("/whatver")
> class FooResource {
>  @SubOfFoo @Inject Provider<BarResource> bar;
>
>  @Path("bar/{id}")
>  public BarResource getBar() { // Should try and add support for 330 @Inject
> for parameters
>   return bar.get();
>  }
> }
>
> Thus specialization is possible without loosing the clear definition of
> sub-resources, and specialization is clearly defined according to Guice
> bindings. Although the above bugs me that there is a dissociation between
> the path parameter, "id", and BarResource.

Yeah.

It also requires that all parent resources are written with
extensibility in mind. You can't just add a new sub-resource anywhere
in the tree of resources. Look how much noise we've just added for one
level of resource depth; imagine 4 or 5 resources deep & how much pain
there is :)


> One way to solve this would be to allow the intermixing of injected and
> passed parameters a bit like Guice's assisted inject, but i cannot come up
> with an appropriately typed and easy solution to that problem independent of
> Guice, and Guice still requires the creation of a factory interface
>
> @Path("/whatever")
> class FooResource {
>  @Inject BarResourceFactory bar;
>
>  @Path("bar/{id}")
>  public BarResource getBar(@PathParam("id") String id) {
>   return bar.create(id);
>  }
> }
>
> interface BarResourceFactory {
>  public BarResource.create(String id);
> }
>
> class BarResource {
>  @Inject
>  BarResource(@Inject FooResource foo, @Assisted String id) { ... }
> }
>
> This is frustrating, i feel we are missing a language feature here that
> could really help.

Yeah - its kinda verbose though having to shove factories everywhere
which only really help the framework implementation; they are just
noise to the application programmer :)


> It is certainly easy to implement support for @ResourceRef (and say
> @SuperResourceRef to validate a parent of a certain type) as we already that
> support for that in a slightly different way.
>
> Style A would be a little harder. Having @SubResource("bar/{id}",
> BarResource.class) would be easier because we don't change the definition of
> what a root resource is.

Fine with me! BTW I'm really not trying to change the definition of
what a root resource is at all - just providing a way to add new sub
resources on to an existing resource.


> I am currently not too sure about the consequences
> of a sub-resource modifying the relationship to a super resource when jar is
> dropped into the classpath. It could make for harder debugging if more magic
> is involved.

Jersey already detects all the root resources on the classpath in the
packages listed; the only real change would be things annotated with
@Path + @SubResource (or whatever) would not be added as roots, but
added as sub resources of their parent's resource type. Which only
have an effect when folks navigate into the parent resource with a new
previously unsupported additional uri template. i.e. it shouldn't
affect root resources per se - or any existing resource, it will only
affect new URIs folks try to navigate to which match the new sub
resource URI templates


> If the super resource is unaware of the sub-resources that
> could be attached it may make it harder to define application-based
> hypermedia representations on the super resource

Note that this new sub-resource mechanism I'm proposing for style A
would only apply to new child resources with an additional URI
template. So it would not affect in any way the available hypermedia
representations on the parent resource.

If I've not been clear my aim is to make it easier to add new sub
resource (i.e. a totally different resource with a different URI) by
appending a URI template to an existing resource (somewhere in the URI
tree) - such that the new sub resource can reuse any existing resource
bean in the tree (i.e. reuse code that does URI template decomposing
and reuse methods on parent resources and so forth) without having to
start from scratch and write a big new root resource that ends up
copy/pasting lots of the logic and URI template code that already
exists in the available resource bean tree.

As you build trees of resource beans; they tend to do more than just
decompose a URI string; they tend to look up a Customer object, then
an Order; the aim is to be able to create a new resource for an Order
for example in a simple extensible way.

A nice side benefit is that it offers a more DRY and IoC consistent
programming model for root and sub resources (much cleaner than style
B and C).


> (although at runtime the
> relationships will be recognized by the WADL representation returned by the
> super resource).

Folks have to define URIs nicely so this kind of extension is
possible. If the URIs are bad such that they are not extensible this
way, its a bug in the users code not in JAXRS/Jersey :)

Maybe the Camel use case is a bit too wacky for you :)

How about just viewing this as an easier way of providing a consistent
programming model for writing resources and sub resources - using the
same injection mechanism without having to write lots of boiler plate
code to place class C within class B within class A; they can just be
linked by an annotation - no noisy factory methods required or noisy
get methods in parent resources which just return the resource they
are given by the framework etc.

I"m not saying we should disallow style B or C; but style A is the
most DRY and modular.


> I am wondering in such cases that perhaps it might be better to define a
> routes class that provides a global view of the relationships?
>
>  resource(Foo.class, "blah).
>    subResources(resource(Bar.class, "b"), resource(Baz.class, "z"))
>
> kind of hard to wire up graphs nicely using Java though.

Whether there's a little routing DSL or whether we use annotations I
don't mind much; but given JAXRS is all annotation based right now I
figured just adding a new annotation to link new sub resources to a
parent resource was nice and simple.

As an aside many web frameworks in the Scala/Ruby/Groovy worlds have
routing DSLs in them. I actually prefer the annotation approach as its
more modular & simpler.


> What if we could wire up the sub-resource to the super-resource but the path
> is defined on the former? that would at least resolve my concerns about the
> "anything goes" relationship and the path would be defined on the
> sub-resource.
>
> @Path("/whatver")
> @SubResource(BarResource.class)
> class FooResource { }
>
> @SubPath("bar/{id}") // Different annotation so as not to conflict with def
> of root resource
> class BarResource {
>  @PathParam("id") String id;
>  @ResourceRef FooResource parentResource;
>
>  @GET String getBody() {...}
> }
>
> It also means one could define sub-resources on sub-resources.

Sorry thats what I meant; a new sub resource would have the uri
template on its own class. (Using a different annotation @SubPath
instead of @Path is fine by me). Then we can add new sub resources to
any resource at any point in the tree (and add new resources to it etc
etc)

The only difference is where the link between the parent and child
classes goes; on the child or on the parent.
Defining all the available types of sub resources on a parent resource
is less loosely coupled (e.g. you'd need to allow now a collection
rather than 1 class. So I can't copy-paste a sub resource and just
change the Uri template and a few methods; I've got to remember to add
a new sub-resources class to a parent's annotation. Plus it makes
extensibility harder as all of the sub resources now must be in the
same classloader; I can't easily for example add an optional GraphViz
or Excel set of resources to an application using an optional library
folks can use (without deriving from every resource class in each
module just to override one annotation - which only works with 1
optional module, not 2).


Let me turn the question around - why are you worried about being able
to add new sub resources to existing root or sub resources by scanning
the classpath; when its fine to add root resources that way?

After all like you said at the start of your reply, there's nothing to
stop someone adding a pseudo sub resource by just copy and pasting the
correct URI template and just adding a bit more stuff on the end?

One of the great things about JAXRS right now is you can decompose
your resource beans into libraries and then create different web
applications using different combinations of libraries and JAXRS
figures out which resource beans are active by scanning the classpath.
Is extending this behavior to allow new sub resources anywhere in the
tree (with new URis) so bad? Afterall adding them doesn't affect any
of the previous URIs; it just makes some previously 404 responses do
something interesting if you add new libraries to the classpath.

-- 
James
-------
http://macstrac.blogspot.com/
Open Source Integration
http://fusesource.com/