users@jersey.java.net

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

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Tue, 3 Aug 2010 10:07:04 +0200

Hi James,

OK, i have a clearer understanding now. You want to introduce is a new
type of component that is registered with Application/ResourceConfig
(how it is registered via scanning or explicitly is not important).
That component will declare that it is a sub resource of a super
resource.

The concern i have around hypermedia is the super-resource may not
know about all the sub-resources such that it can create a
representation with links/types to those sub-resources. I think this
concern can be mitigated by a resource being able to inspect the
model, which would any be better than using Java reflection on
explicit sub-resource locators.

I believe this feature is certainly possible to implement in addition
to ensuring the abstract model is correctly up to date without too
many modifications to existing code. It should also be possible to
make it work for conventional sub-resources that have those new
components attached as further sub-resources.

For Aug/Sept i will be mostly tied up sorting out a new client API
(moving the one in the experimental area to the stable area) and
JavaOne so i don't have much time to work on this at the moment. The
@ResourceRef stuff is easy, 1 to 2 hour job at most.


Of late i have become more uncomfortable with the idea of plonking
jars in place without some form of developer agreement or contract in
place that describes relationships, because the former can lead to
very confusing results and class path hell. This is where i was
suggesting some sort of routes file. But what i really meant was a
module concept much like that of Guice. Imagine if your Camel app
defined a JerseyModule and another app can use that module as a parent
from which it can refer to the components of the parent module. I
think you may be able to do all the same things you can today with
annotations but things might be appropriately scoped e.g. for the case
of a sub-resource declaring the parent resource if there is no
concrete class of that name in the module or parent then it is a
binding error. I think this type of thing can also help with the
inclusion of message body readers/writers e.g. a JAXBModule.
JerseyModule is kind of like Application/ResourceConfig but with
inheritance and builder like registration of stuff (that could include
scanning for registration).

Paul.


On Aug 2, 2010, at 6:26 PM, James Strachan wrote:

> 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/
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>