users@jax-rs-spec.java.net

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

From: Sergey Beryozkin <sberyozkin_at_talend.com>
Date: Wed, 18 Jan 2017 15:58:58 +0000

Just to clarify to avoid the confusion, 2.1-m02 syntax appears to be
quite good after all...

Thanks, Sergey

On 18/01/17 15:53, Sergey Beryozkin wrote:
> 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
>>>>