/rxjava-gwt

RxJava semi-automatic GWT compatibility library

Primary LanguageJavaApache License 2.0Apache-2.0

RxJava GWT

Maven Central Build Status Join the chat

Compatibility pack and minimal GWT dependant code to make RxJava works in GWT. This includes, some missing JDK emulation (most of them from java.util.concurrent). Some minor changes from RxJava that might be eventually applied directly to RxJava. And finally some super-sources and a JavaScript friendly Scheduler to adapt RxJava to the browser.

WARNING GWT version uses JDT 3.11 which contains a bug that makes rxjava 2.x compilation super-slow. This has been fixed but should be integrated first in JDT and later on in the GWT compiler, in the mean time this repo includes a patched version of the last GWT stable version. To use this patched version you need to add the next repository definition and use the GWT version 2.8.2-rx1.

<repository>
    <id>rxjava-gwt-repo</id>
    <url>https://raw.githubusercontent.com/intendia-oss/rxjava-gwt/mvn-repo/</url>
</repository>

Getting started

The best way to getting started with RxJava GWT is to download and run some of the examples like RxSnake, RxBreakout, RxCanvas or just finding for rxjava+gwt in github. Most of them can be tried out cloning and executing mvn gwt:devmode.

You should note that most of the GWT specific utilities are in RxGWT. So you probably want to depend on RxGWT instead of RxJava GWT, which includes common utils like event handlers adapter, request adapters, more advanced schedulers, etc. All those examples depends on RxGWT.

RxGWT contains basic utilities to make arbitrary XHR request, but if you want a typed API or you want to communicate between client and server you should take a look to AutoREST, a REST API lib with RxJava support. Nominatim is a example using the same JAX-RS and RxJava friendly API in JRE (client), JEE (server), Android and GWT.

If you use GWT RPC, you can use AutoRPC to generate RxJava friendly async interfaces automatically.

Download

Releases are deployed to the Central Repository

Snapshots of the development version are available in Sonatype's snapshots repository.

Goals

  • Use same RxJava API in the client side
  • Improve RxJava GWT performance (emulate classes)
  • Make original RxJava project GWT compatible

Source code folders

The 'super' and 'modified' folders are both super-sources, but they are separated because the 'super' contains emulations that can be eventually merged into GWT and 'modified' contains RxJava changes that can be eventually merged into RxJava project. Leaving this project with only GWT specific code and just a few super sources to fix scheduling incompatibilities and reasonable performance improvements.

Profiling with d8

Install V8 and create aliases for d8 and xxx-tick-processor.

mvn -Dd8 package
cd target/d8/perf
d8 -prof --log-timer-events perf.nocache.js
tick-processor --source-map=../../gwt/deploy/perf/symbolMaps/<HASH>_sourceMap0.json v8.log

Install V8 on Mac Profiling GWT applications with v8 and d8 Performance Tips for JavaScript in V8

Why I start this project?

This is an old story not useful to understand anything about the project, hehe but I like to remember why I started it :bowtie:

My primary goal to start this project was to have a shared (between client and server) type safe Promise implementation. This promises most of the time are server request calls, and most of this request returns a collection of items (zero or one are collections too 😬). So I end up with the conclusion that Observables was an elegant solution to my problem. With Observables you can define your shared API and provides a Promise like API to handle and compose responses (composition was the primary motivation to use promises, if you don't need composition callbacks are probably enough). So you can define service like this:

public interface FilesService extends DirectRestService {
    @GET @Path("/files") public Observable<FileVO> files(@QueryParam("matches") String matches);
}

And can be used like:

// simple: request one file and show
filesService.files("/one.file").subscribe(resultBox::showFile);

// advanced: request 10 files each time search box changes, canceling previous and showing the results
Observable<String> searchText = RxUser.bindValueChange(searchBox);
Observable<List<String>> searchResult = searchText
    .switchMap(matches -> filesService
        .files(matches).observeOn(Schedulers.compute())
        .map(Tools::heavyWeightOperation).take(10).toList())
    .share();
searchResult.subscribe(resultBox::showFiles);    

This is pretty awesome and powerful, as RxJava requires subscription and notify un-subscriptions makes request composition easy and safer as you can clean up resources without an annoying API if the request is canceled before it end up. Also, if you have some heavy weight operation, you can process it progressively without locking up the main loop (in the example above done using the observeOn operator), and finally reduce the result into a list to show the final result in a resultBox.

Note: AutoREST GWT implements the shareable JAX-RS interface using RxJava in the client side and RxGWT exposes a lot of common tools like the 'RxUser.bindValueChange' in the code example.