users@jax-rs-spec.java.net

[jax-rs-spec users] Re: JAX-RS Client Reactive API review

From: Markus KARG <markus_at_headcrashing.eu>
Date: Sat, 14 Jan 2017 00:34:28 +0100

You did not get it wrong but miss one point. I assume nobody wants to mix up reactive and non-reactive style within the same application. So in fact my proposal is to have completely separated APIs in the end, which typically share similar method names and fluent style, but do not provide any possibility to switch from synchronous call to reactive call. I do not see any need for mixing styles.

 

From: Ondrej Mihályi [mailto:ondrej.mihalyi_at_gmail.com]
Sent: Samstag, 14. Januar 2017 00:31
To: jsr370-experts_at_jax-rs-spec.java.net
Subject: Re: [jax-rs-spec users] Re: JAX-RS Client Reactive API review

 

My counterproposal is to provide an additional RxClient class which always produces reactive invocations, and keep the normal Client untouched.

 

I don't think this would be a clean solution. It would mean to duplicate every downstream interface to provide rx invocation builder after request() is called. Moreover, the current API clearly separates how the request is built from how it is invoked. I can only imagine an easy solution with a non-fluent API ( RxClient.request(webTarget) )

Any fluent API would suffer from API duplication - in other words fragmentation. It would be hard to create a target in one method, and pass the target to another method, which would issue the request - the 2 methods would be obviously coupled. Or did I get it wrong?

Ondrej

 

2017-01-13 23:56 GMT+01:00 Markus KARG <markus_at_headcrashing.eu>:

Pavel,

 

thank you for sharing the code examples.

 

In fact I don't know if you actually want us to repeat our arguments, but here is my personal judgement of the proposed RX API:

 

* The decision to make CompletableStage the default and most simple way to use RX in JAX-RS is appreciated, as it will never go away, due to de-facto being the sole RX interface in the Java world which is part of the JRE and / or any JCP standard currently and in near future.

 

* I don't like the rx() method which changes from "synchronous" to "reactive" invocation. I doubt that anybody would love to repeat rx() again and again, and I doubt that people want to write programs that shares sync and rx style invocations within the same code block. My counterproposal is to provide an additional RxClient class which always produces reactive invocations, and keep the normal Client untouched.

 

* I don't like the need to write down the type of custom RX invoker type again and again. I doubt that people really will write software which shares CompletableStage, RxJava, Guava etc. within the same code block. I assume that people instead will write full applications in *either* CompletableStage *or* RxJava *or* Guava etc (so they decide per app, not per invocation). The resulting application source code will be easier to read and potentially less error-prone if there instead would be an SPI to replace JAX-RS's reactive provider at deploy time, e. g. from the default CompletableStage to RxJava Observable.

 

* The proposal only contains reactive support for the client API. I want to rise the question whether it might be a good idea to also extend server-sided async support at the same time. My proposal is to allow Future<T> as a return type of resource methods, so it is pretty easy to do concise async code like the example below (if we enforce CompletableFuture instead of CompletableStage). The idea is to get rid of the async boilerplate and the need to explicitly wait for the result of the RX invocation, but just to tell JAX-RS to set up the precessing chain and let it execute in the background by Java EE's default ManagedExecutorService (hence outside of the scop of the code block, hence outside the HTTP thread pool):

 

@GET public Future<List<String>> collectResultsFromOtherServers() {

   return client.target("remote/forecast/{destination}")
                .resolveTemplate("destination", "mars")
                .request()
                .header("Rx-User", "Java8")
                .rx()
                .get(new GenericType<List<String>>() {
                });
/*
 * Certainly the actual idea is to combine many parallel invocations instead of simple returning one!
 */

}

 

-Markus

 

 

From: Pavel Bucek [mailto:pavel.bucek_at_oracle.com]
Sent: Freitag, 13. Januar 2017 21:36
To: jsr370-experts_at_jax-rs-spec.java.net
Subject: JAX-RS Client Reactive API review

 

Dear experts,

please review following wiki and APIs:

https://java.net/projects/jax-rs-spec/pages/RxClient

All added classes related to Reactive Client APIs are linked from that page, but let me allow a short recap.

JAX-RS Client is being extended by the ability to provide a way how to process responses in reactive fashion. The change consists of:

- adding rx(...) methods to Invocation.Builder
- defining RxInvoker
- allowing users to extend this API by providing RxInvokerProvider

Specification will mandate implementation for CompletionStage from Java SE 8.

Client code examples:

- basic use

CompletionStage<List<String>> cs =
        client.target("remote/forecast/{destination}")
                .resolveTemplate("destination", "mars")
                .request()
                .header("Rx-User", "Java8")
                .rx() // gets CompletionStageRxInvoker
                .get(new GenericType<List<String>>() {
                });
 
cs.thenAccept(System.out::println);
 

- using custom RxInvokerFactory (this is little artificial, since the factory just returns CompletionStageRxInvoker, but support for Observable from RxJava or ListenableFuture from Guava can be done in the exact same manner)

CompletionStage<List<String>> cs =
        client.target("remote/forecast/{destination}")
                .resolveTemplate("destination", "mars")
                .request()
                .header("Rx-User", "Java8")
                .rx(CompletionStageRxInvokerProvider.class)
                .get(new GenericType<List<String>>() {
                });
 
cs.thenAccept(System.out::println);

 

Source links:

- https://github.com/jax-rs/api/blob/2.1-m02/jaxrs-api/src/main/java/javax/ws/rs/client/Invocation.java#L298
- https://github.com/jax-rs/api/blob/2.1-m02/jaxrs-api/src/main/java/javax/ws/rs/client/RxInvoker.java
- https://github.com/jax-rs/api/blob/2.1-m02/jaxrs-api/src/main/java/javax/ws/rs/client/RxInvokerProvider.java

Examples & tests:

- https://github.com/jax-rs/api/blob/2.1-m02/jaxrs-api/src/test/java/javax/ws/rs/core/RxClientTest.java
- https://github.com/jersey/jersey/blob/2.x/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java#L86

The last link is to the Jersey repository. Jersey version 2.26 will be JAX-RS 2.1 RI and branch 2.x is where the development will happen. Jersey 2.26-b01 (which is being released right now) implements all rx(...) methods; feel free to test/evaluate it there.

Looking forward to your feedback!

Thanks and regards,
Pavel