Now that I think about it, we do repeatedly pass a parameter to rx()
even in this case, the only difference is that, assuming the below
issues get resolved,
it would be something like CompletionStage.class as opposed to
SomeRxInvokerProvider.
Given that rx() covers the default case and the current syntax allows
for the custom RxInvoker methods, it does appear to be the viable option
which we should probably settle on...
Sergey
On 18/01/17 15:43, Pavel Bucek wrote:
>
> Hi Ondrej,
>
> we have a "copy" of TypeLiteral in JAX-RS - see class GenericType.
>
> The problem here is that I don't see how that solves the issue. The
> problem is type of the instance we are trying to return (as opposed to
> parameter ). Note that this:
>
> CompletionStage<UserPojo> cs =
> rxClient.target("remote/forecast/{destination}")
> .resolveTemplate("destination","mars")
> .request()
> .header("Rx-User","Java8")
> .rx(CompletionStage.class)
> .get(new GenericType<CompletionStage<UserPojo>>{});
>
>
> Still returns only CompletionStage<?>, because get method is declared as:
>
> public <R>T get(GenericType<R> responseType);
>
> (T is CompletionStage in this case, R is CompletionStage<UserPojo>).
>
> To fix this, we can change get to:
>
> public <R>R get(GenericType<R> responseType);
>
> The issues I do se:
>
> - you are repeating CompletionStage.class (once as rx(..) param
> and once as generic param of GenericType)
> - what should happen when you do following?
>
> CompletionStage<UserPojo> cs =
> rxClient.target("remote/forecast/{destination}")
> .resolveTemplate("destination","mars")
> .request()
> .header("Rx-User","Java8")
> .rx(CompletionStage.class)
> .get(new GenericType<*Flowable*<UserPojo>>{});
>
> - what should happen when you do following?
>
> CompletionStage<UserPojo> cs =
> rxClient.target("remote/forecast/{destination}")
> .resolveTemplate("destination","mars")
> .request()
> .header("Rx-User","Java8")
> .rx(CompletionStage.class)
> .get(UserPojo.class);
>
> (this version doesn't "force" the type, so it is possible to write
> infinite number of "wrong" API calls.. compare it to what we already
> have in JAX-RS client.)
>
> Regards,
> Pavel
>
> On 18/01/2017 16:18, Ondrej Mihályi wrote:
>> Hi Pavel,
>>
>> I appreciate you have provided an example. I agree this
>> straightforward approach is not directly supported by Java syntax.
>>
>> This is the same problem, which is solved in CDI by
>> javax.enterprise.util.TypeLiteral
>> <https://docs.jboss.org/cdi/api/1.0/javax/enterprise/util/TypeLiteral.html>.
>> I think we would have to use the same option. I'm not sure if JAX-RS
>> can use the package javax.enterprise.util and the TypeLiteral, which
>> is defined by the CDI spec.
>>
>> I would still prefer this declarative option than having to provide
>> the real provider by the developer each time rx() method is called.
>>
>> Ondrej
>>
>> 2017-01-18 10:54 GMT+01:00 Pavel Bucek <pavel.bucek_at_oracle.com
>> <mailto:pavel.bucek_at_oracle.com>>:
>>
>> Alright :)
>>
>> After having a chat with Santiago, I tried to prototype "real
>> provider" approach, which would result in code like:
>>
>> Client rxClient =client.register(CompletionStageRxInvokerProvider.class);
>>
>> CompletionStage<UserPojo> cs =
>> rxClient.target("http://foo.bar" <http://foo.bar>)
>> .request()
>> .rx(CompletionStage.class)
>> .get(UserPojo.class);
>>
>> (let's not talk about built-in support for CompletionStage and
>> consider this as a valid extension, provided by
>> CompletionStageRxInvokerProvider registered to the client).
>>
>> The major change here is the "rx" method signature, which would be:
>>
>> public interface Invocation {
>> // ...public static interface Builderextends SyncInvoker {
>>
>> // ...public <T> RxInvoker<T> rx(Class<T> clazz);
>> }
>> }
>>
>> The major change here is the return type. It is no longerT ?
>> extends RxInvoker, it is RxInvoker<T>. And that brings and issue
>> I don't know how to deal with. To be able to do the example code
>> (first code snippet), we'd need something like:
>>
>> public interface RxInvoker<T> {
>>
>> // ...public <R>T<R> get(Class<R> responseType);
>>
>> }
>>
>> Problem is that this is not a valid Java syntax. We simply cannot
>> do T<R>. Let's compare that to previous proposal:
>>
>> public interface Invocation {
>> // ...public static interface Builderextends SyncInvoker {
>>
>> // ...public <T extends RxInvoker>T rx(Class<?extends RxInvokerProvider<T>> clazz); }
>> }
>>
>> public interface RxInvoker<T> {
>>
>> // ...public <R>T get(GenericType<R> responseType);}
>>
>> The main difference (and the reason why it works) is the return
>> type if Invocation.Builder#rx(..) is an instance of subclass of
>> RxInvoker, not of a RxInvoker<T>. That allows to override return
>> type of RxInvoker#get(..) method, exactly as it is done in
>> CompletionStageRxInvoker:
>>
>> public interface CompletionStageRxInvokerextends RxInvoker<CompletionStage> {
>>
>> // ...
>> @Override public <T> CompletionStage<T> get(Class<T> responseType);
>>
>> }
>>
>> Does anyone know how to solve this issue? (because if not, I
>> don't see how we can design/support "real provider" case). I'm
>> looking forward to any comments. If you want to play with latest
>> change, feel free to clone [1], the example is [2],
>> Invocation.Builder#rx [3] and RxInvoker [4]. Thanks and regards,
>> Pavel [1] https://github.com/pavelbucek/jax-rs
>> <https://github.com/pavelbucek/jax-rs> [2]
>> https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/test/java/javax/ws/rs/core/RxClientTest.java#L110
>> <https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/test/java/javax/ws/rs/core/RxClientTest.java#L110>
>> [3]
>> https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/main/java/javax/ws/rs/client/Invocation.java#L338
>> <https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/main/java/javax/ws/rs/client/Invocation.java#L338>
>> [4]
>> https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/main/java/javax/ws/rs/client/RxInvoker.java#L86
>> <https://github.com/pavelbucek/jax-rs/blob/rx-client/jaxrs-api/src/main/java/javax/ws/rs/client/RxInvoker.java#L86>
>> On 17/01/2017 17:41, Ondrej Mihályi wrote:
>>> +1
>>> ||
>>> 2017-01-17 16:57 GMT+01:00 Santiago Pericasgeertsen
>>> <santiago.pericasgeertsen_at_oracle.com
>>> <mailto:santiago.pericasgeertsen_at_oracle.com>>:
>>>
>>>> On Jan 13, 2017, at 6:19 PM, Ondrej Mihályi
>>>> <ondrej.mihalyi_at_gmail.com
>>>> <mailto:ondrej.mihalyi_at_gmail.com>> wrote:
>>>> Actually, I like the unwrap method more than the current
>>>> proposal. It makes it explicit what I want to get when I
>>>> write code. The current proposal is similar, but requires
>>>> me to remember the name of the invoker on top of the rx
>>>> interface I want to get.
>>>> Compare:
>>>> _Current proposal _
>>>> CompletionStage<List<String>> cs = client.request()
>>>> .rx(CompletionStageRxInvokerProvider.class)
>>>> .get(new GenericType<List<String>>() {
>>>> });
>>> Perhaps we should explore turning this into a "real
>>> provider”. I.e., something that is registered in the runtime
>>> and looked up by the JAX-RS implementation. In which case,
>>> the param to rx() could be CompletionStage.class instead.
>>> This would be more inline with, say, ParamConverters.
>>> — Santiago
>>>