jsr339-experts@jax-rs-spec.java.net

[jsr339-experts] Re: Refactoring out generic invocations

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Mon, 29 Aug 2011 17:27:58 +0200

On 08/29/2011 03:06 PM, Bill Burke wrote:
>> 2. Removing the header mutators from the Invocation and extending RequestHeaders.Builder once again decreases
>> consistency of the flow context.
>>
>
> How does it decrease consistency? I guess you're trying to separate entity headers from request headers via the Entity
> class? (BTW, "Link" is an entity header and can be used in a request or response).

What I meant is that suddenly the multiple accept(...) or entity headers e.g. type(...) are possible in a single chain.
Of course, it's not the same level as "client.target().invoke()" or "client.target().method("PUT").get()" issues though.

As for Link, since it is specified in it's own specification, I tend to see it as a separately modelled concept. Also,
similarly to some other entity headers, Link seems to make more sense on the response. Are there any known use-cases for
Link in the request?

>
>> 3. The ability to produce generic and fully flexible/mutable invocations is completely lost in exchange for interface
>> reduction.
>>
>
> Interface reduction == easier to read and understand what is going on. This is the whole point of this exercise.

Invocation covers currently a more-advanced less likely use-case scenarios. It still seems quite useful and it does not
really adds any confusion IMO.

Btw., if you really want to focus on reducing interfaces, I'd appreciate your help in attempt to merge Request with
HttpRequest as well as Response and HttpResponse. That's something that truly bugs me. Something, which - in terms of
JAX-RS API - would be a *real* simplification. (Similarly, HttpHeaders and RequestHeaders should be merged, but that
should not be such a big problem.)

>
>> 4. The proposed Invocation interface encapsulates multiple concerns reducing the cohesion of its API. It's not the only
>> class in JAX-RS with such problem, but it's the most exposed class to the everyday users that has the problem.
>>
>
> Well, that's certainly your opinion, not mine. My opinion is that the most exposed class to everyday users should be
> the most easiest to use *and* understand. The class hierarchies you've proposed so far are spaghetti.
>

Assuming resources identified via URIs are the core REST concept, Target would perhaps be the most exposed client-side
class. Be that as it may, Invocation is certainly not the most exposed class in my class hierarchy.

As for the spaghetti code, consider a simple get request (disregarding returned HttpResponse):

ClientFactory.newClient().target(...).request("text/plain").get();

In my API, following 6 interfaces are involved: ClientFactory, Client, Target, Invocation.Builder, SyncInvoker, Configurable
In your API, following 6 interfaces are involved: ClientFactory, Client, Target, Invocation, RequestHeaders.Builder,
Configurable

In case of put/post, it would be 7:7 due to the Entity coming in the picture. Assuming we can agree that those are the
most exposed use cases, I wonder where is the interface spaghetti in the current proposal that is improved by your version?

My main point is that Invocation is out of the way for the most exposed use cases, but it would be a real pity to drop
it from the API completely as it exposes a really nice feature and a lot of extra flexibility if needed.

Marek

>
>> All of he above in exchange for a reduction by 2 interfaces that are typically invisible to the end user anyway. Why
>> would we sacrifice a nice feature (generic invocation) that doesn't cost virtually anything and does not interfere with
>> the main API scenarios, while providing a nice low-level flexibilty if needed, is beyond me. But that's just my take on
>> it. I'd like to see some feedback from other experts.
>>
>
> Well, my previous proposal (Invocation extending HttpRequest) pretty much has all the flexibility you want, with a
> reduced understandable class hierarchy, separation of concerns, with a tiny bit of inconsistency that nobody outside of
> this list will care about. I'd rather suffer a tiny bit of inconsistency instead of having multiple ways to do the same
> exact thing.
>
>> FWIW, target.async(...) doesn't read as good, as Target.request()[.async()] IMO, but if people think it's useful, I can
>> add such shortcut: AsyncInvoker Target.async(...);
>>
>
> request().async().get();
>
> vs.
>
> async().get();
>
> Both are fine for me, I don't really care.
>
> Finally, I did this exercise to show that generic invocations are one of the things that are seriously complicating the
> API. (A complication that wouldn't exist if you weren't so stubborn on the fluent api).
>