users@jax-rs-spec.java.net

[jax-rs-spec users] Re: JAX-RS 2.1 - work schedule

From: Pavel Bucek <pavel.bucek_at_oracle.com>
Date: Fri, 20 Jan 2017 15:27:05 +0100

Hi Ondrej,

I like your determination and consistency.

Unfortunately, I have to strongly disagree with your last proposal.
GenericType is nothing more than a standardized hack, which has limited
usability and should be avoided if possible. Here, we do have that option.

Ad limited usability: imagine that user of the API will wrap your code
in generic method, replacing List<String> with T. Then the information
passed to the rx method will be exactly CompletionStage<T>, which cannot
be used by the implementation for selecting the correct provider. Also,
the code is (no offense) quite hard to write and read - we don't want to
force anyone to write "Foo<Bar<Baz<Qux>>>". (I always wanted to use
"qux" somewhere!)

I believe that the last variant brought up by Santiago fits nicely with
existing APIs and uses already established provider pattern. I'd
appreciate if you could evaluate it, maybe try to use it and share your
thoughts once again.

Thanks and regards,
Pavel


On 20/01/2017 12:56, Ondrej Mihályi wrote:
> Pavel raised a valid point, but it can really be solved by the
> GenericType class, just moving the usage of the GenericType from
> method get to method rx.
>
> Here is a compilable and type-safe solution:
>
> client.target("remote/forecast/{destination}")
> .resolveTemplate("destination","mars")
> .request()
> .header("Rx-User","Java8")
> .rx(new GenericType<CompletionStage<List<String>>>())
> .get();
>
> with the new rx() method on Invocation.Builder defined simply like this:
>
> public <T> RxInvoker<T> rx(GenericType<T> type);
>
> You can play with the code in my fork here:
> https://github.com/OndrejM/api/blob/reactive_provider_by_return_type/jaxrs-api/src/test/java/javax/ws/rs/core/RxClientTest.java#L105
>
>
> However, this solution also provides cons:
> - it is uglier at first sight (although GenericType is always
> necessary at some point sooner or later)
> - once converted to CompletionStage with proper type, it's not
> possible to retrieve the generic Response object in a typesafe way
> (making the methods like get(Class<R>) and get(GenericType<R>
> redundant - but maybe it;s a good thing and simplifies the RxInvoker
> interface)
>
>
> The ugly part can be simplified by any developer using a class that
> extends GenericType like this (the code in my fork already shows that):
>
> class CompletionStageType<T>extends GenericType<CompletionStage<T>>
>
> And I don't think that the second drawback matters - if interested in
> Response, it can be retrieved by
>
> .rx(new GenericType<CompletionStage<Response>() {})
> .get();
> and converted later if needed.
>
>
> Ondrej
>
> 2017-01-19 19:31 GMT+01:00 Santiago Pericasgeertsen
> <santiago.pericasgeertsen_at_oracle.com
> <mailto:santiago.pericasgeertsen_at_oracle.com>>:
>
>
>> On Jan 19, 2017, at 1:12 PM, Markus KARG <markus_at_headcrashing.eu
>> <mailto:markus_at_headcrashing.eu>> wrote:
>>
>> Because in that "more complex" style you can write this then…
>> Client rxClient =*client*.register(Java8.*class*);// i.
>> e.*technically*a CompletionStageRxInvokerProvider, which
>> effectively is part of JAX-RS!!!
>> CompletionStage<UserPojo> cs =
>> rxClient.target(*"http://foo.bar" <http://foo.bar/>*)
>> .request()
>> .rx(CompletionStage.*class*)
>> .get(UserPojo.*class*);
>> …so the average programmer clearly understands that this
>> will/register Java 8/as one possible RX provider (possibly in
>> addition to others), so he can/get a//CompletionStage/.
>> It/feels/just more correct and simple, particular for JAX-RS
>> beginners.
> Of course, but the point raised by Pavel is that this code again
> cannot (at least not obviously) be accepted by the Java type
> checker. Hence, the less desirable suggestion. Please read the
> rest of the e-mail thread.
> — Santiago
>> They will not understand why they shall repeat/_the
>> provider_/again and again, and they will not understand
>> whyrx(T)will return*not*returnT. But I think they will accept to
>> repeat/the stage/again and again, as stages are not reusable
>> (they are used to do that with stages already).
>> -Markus
>> *From:*Santiago Pericasgeertsen
>> [mailto:santiago.pericasgeertsen_at_oracle.com
>> <mailto:santiago.pericasgeertsen_at_oracle.com>]*Sent:*Donnerstag,
>> 19. Januar 2017 16:55 *To:*jsr370-experts_at_jax-rs-spec.java.net
>> <mailto:jsr370-experts_at_jax-rs-spec.java.net> *Subject:*Re:
>> [jax-rs-spec users] JAX-RS 2.1 - work schedule
>> Hi Pavel,
>> Just catching up with this issue. I guess the two levels of
>> indirection has led us into a generic wall :)
>>> Client rxClient
>>> =*client*.register(CompletionStageRxInvokerProvider.*class*);
>>> CompletionStage<UserPojo> cs =
>>> rxClient.target(*"http://foo.bar" <http://foo.bar/>*)
>>> .request()
>>> .rx(CompletionStage.*class*)
>>> .get(UserPojo.*class*);
>> So what if we reduce indirection and write:
>> .rx(CompletionStageRxInvoker.class)
>> as before, still keeping the provider for it? Less ideal of course.
>> — Santiago
>