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

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

From: Pavel Bucek <pavel.bucek_at_oracle.com>
Date: Wed, 18 Jan 2017 16:43:04 +0100

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
>>