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

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

From: Ondrej Mihályi <ondrej.mihalyi_at_gmail.com>
Date: Fri, 20 Jan 2017 18:07:08 +0100

Thanks for your honesty, Pavel.

I didn't mean to propose a final solution, just a proof that the approach
suggested by me and Markus can work.

What I'm after is really the consistency - Java EE API is mostly about
standardizing what should be done and not how. Therefore it is more natural
for me to declare that I want to use CompletionStage, RxJava or
whatever, rather than to define how to do this conversion by passing a
converter each time I want to use it. Even more if the converter is meant
to be provided by the implementation and not by users of the API.

I accept that my solution is not perfect, I just wanted to point out that
the approach is possible.

I agree that the last suggestion by Santiago is the best solution so far.
For me it is important not to pass any implementation to rx() method, and
the solution of .rx(CompletionStageRxInvoker.class) meets that. The
developer jut needs to write an empty interface, jut to define proper type
conversions, which is nice (except that awful number of methods to
override, but I have no energy now to try to propose something better to
reduce the number :) )

Thanks for the discussion :)
Ondrej

2017-01-20 15:27 GMT+01:00 Pavel Bucek <pavel.bucek_at_oracle.com>:

> 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>:
>
>>
>> On Jan 19, 2017, at 1:12 PM, Markus KARG <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 why rx(T) will return *not* return T.
>> 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.pericasgeerts
>> en_at_oracle.com <santiago.pericasgeertsen_at_oracle.com>] *Sent:* Donnerstag,
>> 19. Januar 2017 16:55 *To:* 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
>>
>>