Hi Markus,
I'm not sure whether you were able to follow the whole thread, but
please look at this post:
https://java.net/projects/jax-rs-spec/lists/jsr370-experts/archive/2017-01/message/81
In short - we tried to do it with rx(Pavelable.class), but it doesn't
fit in current API, since generics doesn't allow us to sufficiently
define the return type. (it about returning RxInvoker<T> vs ? extends
RxInvoker; more details in the original thread).
If you are able to keep the rx() method in the chain as it is and do it
in a way that we can pass only Pavelable.class, I'm all ears.
Thanks and regards,
Pavel
On 22/01/2017 13:51, Markus KARG wrote:
>
> Pavel,
>
> besides all technical issues your proposal certainly does solve,
> infact I strongly dislike the idea that an application programmers has
> to type the word "Pavelable/Invoker/.class" but would stronlgy love to
> type the word "Pavelable.class" instead. The first approach certainly
> is absolutely correct and logical, but the latter is, what people
> actually want to say: "Give me a /CompletionStage/". Nobody says "Give
> me a CompletionStage/InvokerProvider/" in the real world, despite the
> technical fact that this is what he technically has to do.
>
> My proposal would be to make this user-oriented simplification
> possible if we find a technical way to solve this. If we don't then we
> just have to live with your proposal as-is.
>
> -Markus
>
> *From:*Pavel Bucek [mailto:pavel.bucek_at_oracle.com]
> *Sent:* Sonntag, 22. Januar 2017 12:09
> *To:* jsr370-experts_at_jax-rs-spec.java.net
> *Subject:* Re: [jax-rs-spec users] Re: JAX-RS 2.1 - work schedule
>
> Hi Ondrej,
>
> just a note:
>
> 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
> :) )
>
> The developer won't be writing any interface - it won't work if he
> will do that. He needs to use exactly the same interface which is
> provide as part of the "extension implementation", so for example if
> there is a library with support for "org.pavel.Pavelable<T>", it contains:
>
> * org.pavel.PavelInvoker implements RxInvoker<Pavelable>
> * org.pavel.PavelProvider implements RxInvokerProvider<PavelInvoker>
>
> and the code will always look like:
>
> Client client = ClientBuilder./newClient/();
> client.register(org.pavel.PavelableProvider.*class*);
> Pavelable<Response> csResponse =
> client.target(*"http://oracle.com" <http://oracle.com>*)
> .request()
> .rx(org.pavel.PavelableInvoker.*class*)
> .get();
>
>
> Simply because underlying client runtime does a lookup for provider
> for a class PavelableInvoker, which in this case would be something like:
>
> *public static class *PavelableProvider *implements *RxInvokerProvider<PavelableInvoker> {
> @Override
> *public boolean *provides(Class<?> clazz) {
> *return *Pavelable.*class*.equals(clazz);
> }
> @Override
> *public *PavelableInvoker getRxInvoker(SyncInvoker syncInvoker,
> ExecutorService executorService) {
> *return *///...;/
> //}
> }
>
>
> (note the "provides" method).
>
> hope the proposal is clearer now. Please let me know if that changed
> anything about how you like it :).
>
> Best regards,
> Pavel
>
>
> On 20/01/2017 18:07, Ondrej Mihályi wrote:
>
> 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
> <mailto: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
> <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]*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
>