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

[jsr339-experts] Re: Some comments about Target and Invocation

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Thu, 01 Sep 2011 13:55:14 +0200

On 09/01/2011 01:06 PM, Sergey Beryozkin wrote:
> On 01/09/11 11:31, Marek Potociar wrote:
>> int[] bookIndexesToRetrieve = ...;
>> Target booksResource = client.target("http://books/");
>> List<Book> books = new ArrayList(bookIndexesToRetrieve.length);
>> for (int bookIndex : bookIndexesToRetrieve) {
>> books.add(booksResource.path(String.valueOf(bookIndex)).request("text/plain").get(Book.class));
>> }
>
> Won't the above result in "http://books/1/2/3/4" say after 4 iterations ? I'm presuming that target.path() is
> accumulative, that is calling target.path("1") is equivalent to target.path("1").path("1").path("1").path("1") ?

No, Target is *NOT* mutable (unlike Invocation.Builder or HttpRequest). IOW:

Target t1 = client.target("http://books");
Target t2 = t1.path("1");
t1 != t2; // !!!

>
>>
>> Or alternatively via path templates:
>>
>> int[] bookIndexesToRetrieve = ...;
>> Target bookResource = client.target("http://books/{id}");
>> List<Book> books = new ArrayList(bookIndexesToRetrieve.length);
>> for (int bookIndex : bookIndexesToRetrieve) {
>> books.add(bookResource.pathParam("id", String.valueOf(bookIndex)).request("text/plain").get(Book.class));
>> }
>>
>
> I guess this should work...q
>
>> I don't see the need for back() here.
>>
> This time I was more after seeing if a transition from Target to Request can be problematic or not. It would probably
> help in the 1st example (assuming I'm correct about path() being accumulative unless a template var is used)

Again, Target is not mutable. Not even in case of template paths. Each Target method is supposed to return an instance
that may be usable independently.

>
> Repeating the same request("text/plain") is not a big deal, the flow would see more duplications in case of repetitive
> posts, not a big deal I guess too - just not optimal.
>
> We have to repeat request(...) because of course we can't set path() once we moved to this next request stage.
>
> I think I'd prefer seeing
>
> Target booksResource = client.target("http://books/{id}");
> for (int bookIndex : bookIndexesToRetrieve) {
> books.add(bookResource.pathParam("id", String.valueOf(bookIndex)).accept("text/plain").get(Book.class));
> }
>
> which could be optimized further to:
>
> Target booksResource = client.target("http://books/").accept("text/plain");
> for (int bookIndex : bookIndexesToRetrieve) {
> books.add(bookResource.pathParam("id", String.valueOf(bookIndex)).get(Book.class));
> }

Now you just stopped producing a well-formed HTTP GET request as it does not have an Accept header. I don't think we
want to encourage that.

>
> This is why I liked a nearly perfect revision involving Target.prepare.
> Just curious, would Entity thing work in that revision ?

Yes. But the problem with well-formed HTTP GETs would be there too.

>
> Also I start thinking about the current Target to Invocation to get/etc support being not a complete API per se but a
> customized API covering basic GET/POST cases. As soon as we want to set even a basic custom header then we are forced to
> move into that unfriendly Invocation/HttpRequest world with method("GET").invoke(), etc.

If you checked the examples or at least looked at the Invocation.Builder API, you would notice the
Invocation.Builder.header(...) method.

>
> But I promise, I will check the examples next :-)

Yes, you most certainly should do it. I am ready to clarify any questions around the API or examples, but I prefer
experts do some self-study first.

>>>
>>> 2. Similarly to one, but using a query param.
>>
>> Very similar code to the above:
>>
>> int[] bookIndexesToRetrieve = ...;
>> Target booksResource = client.target("http://books");
>> List<Book> books = new ArrayList(bookIndexesToRetrieve.length);
>> for (int bookIndex : bookIndexesToRetrieve) {
>> books.add(booksResource.queryParam("id", String.valueOf(bookIndex)).request("text/plain").get(Book.class));
>> }
>>
>> Again, no need for back().
>>
> Yes, back() would be non-appropriate here. queryParam, is it accumulative or not ? How do we express "?id=1&id=2" ?

All Target URI-related methods work the same way as their's counterparts in UriBuilder. The only difference is that the
returned Target instance is not the same (different URI, different Target instance).

HTH,
Marek

>
>>>
>>> I think the fluent API should be flexible enough to accommodate for repetitive invocations against the same targetURI
>>> without forcing a user to retype things which are shared across requests, ex, an accept type, base URI, Content-type.
>>
>> It is - via path templates or via query params.
>>
>>>
>>> Can you give me a favor and actually type some code showing how say 1 can be done, please don't hesitate to use BFS or
>>> DFS techniques
>>
>> I didn't have to use DFS or BFS for such simple case. Give me a more complex problem! :)
>>
> Sounds good :-)
> Sergey
>
>> Marek
>
>