Java libraries you can't afford to miss notes

(This notes is from watching on Java Libraries You Can’t Affort to Miss on JavaOne)

Introduction

All of libraries in this talk are open sourced, and they are working pretty good.

The Challenge

  • Write an application that consumes a REST API
  • Components must be small and reusable
  • Say not to boilderplate code
  • Behavior should be easy to test

The libraries

  • Production: Guice, OkHttp, Retrofit, JDeferred, RxJava, Mbassador, Lombok, Slf4j
  • Test: JUnitParams, Mockito, Jukito, Awaitility, Spock, WireMock

The slides are using GitHub API as example, quering repositories.

And we’ll need:

  • Dependency Injection
  • HTTP client & REST behavior
  • JSON mapping
  • Boilerplate buster
  • Handle concurrency

The code is on https://github.com/aalmiray/javatrove

Dependency Injection

Guice

  • Reference implementation for JSR-330
  • Using Guice to bind types, instances, and constant values
  • Can provide lazily evaluated instances, i.e, providers

Also you should use Guava with Guice

And also… Spring

Behavior

Logging

SLF4F wraps all other logging frameworks:

  • java.util.logging
  • Apache Commons Logging
  • Apache Log4j
  • Provides varargs methods

HTTP

OkHttp: http://square.github.io/okhttp

  • Basic HTTP/HTTP2 client API
  • Configuration is extensible via factory classes
  • HTTP lifecycle be decorated via interceptors

Adding Java on top of HTTP?

Retrofit: http://sqaure.github.io/retrofit

1
2
3
4
5
6
7
public interface GithubAPI {
@GET("/orgs/{name}/repos")
Call<List<Repository>> repositories(@Path("name") String name);
@GET
Call<<List<Repository>> repositoriesPaginate(@Url String url);
}
1
2
3
4
5
6
7
8
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(
JacksonConverterFactory.create(objectMapper))
.build();
return retrofit.create(GithubAPI.class);
...
githubApi.repositiories("foo");
  • Wraps REST calls with Java interfaces
  • Extensible via factories
  • Relies on OkHttp

Multi-threaded code

Golden rule of UI programming:

  • Everything related to UI must be executed inside the UI thread (read/write UI properties, paint/repaint, etc)
  • Everything else must be executed outside of the UI thread

JDeferred

http://jdeferred.org

1
2
3
public interface Github {
Promise<Collection<Repository>, Throwable, Void> repositories(String name);
}

Create a promise:

1
2
3
4
5
6
7
8
9
public Promise<Collection<Repository>, Throwable, Void> repositories(final String name) {
return defferedManager.when(() -> {
Response<List<Repository>> response = api.repositories(name).execute();
if (response.isSuccess()) {
return response.body();
}
throw new IllegalStateException(response.message());
});
}

Consume the promise:

1
2
3
4
github.repositories(model.getOrganization(), limit)
.progress(model.getRepositories()::add)
.fail(Throwable::printStackTrace)
.always((state, resolved, rejected) -> model.setState(READY));
  • Delivers the concept of promises
  • Promises can be chained
  • Java 8 friendly
  • One shot execution

Reactive programming

Reactive programming is a new name for old and well-known concepts: Events and streams

RxJava

http://reactivex.io

1
2
3
4
5
6
7
8
9
10
11
12
13
Observable<Repository> observable =
github.repositories(model.getOrganization());
if (model.getLimit() > 0) {
observable = observable.take(model.getLimit());
}
Subscription subscription = observable
.timeout(10, TimeUnit.SECONDS)
.doOnSubscribe(() -> model.setState(RUNNING))
.doOnTerminate(() -> model.setState(READY))
.subscribeOn(Scheduluers.io())
.subscribe(model.getRepositories()::add, Throwable::printStackTrace);
model.setSubscription(subscription);

Retrofit + RxJava

1
2
3
4
5
6
7
public interface GithubApi {
@GET("/orgs/{name}/repos")
Observable<Response<List<Repository>>> repositories(@Path("name") String name);
@GET
Observable<Response<List<Repository>>> repositoriesPaginate(@Url String url);
}
1
2
3
4
5
6
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(GithubAPI.class);
  • Implements the observable pattern
  • Delivers dozens of operations out of the box: e.g. zip, reduce, concat
  • Support backpressure, i.e. when the data producer is faster than the data consumer

Component Communication

  • How do you keep two unrelated components communicated with one another?
  • How do you push data down the stream without forcing publishers to wait for consumers?

MBassador

https://github.com/bennidi/mbassador

  • Configurable event bus based on annotations
  • Faster implementation than Guava’s event buss
  • NOT: project is NOT actively maintained

Bytecode / AST

Lombok

https://projectlombok.org

sounds like @AutoValue?

  • Reduce boilerplate source code by generating bytecode
  • Relies on APT (Annotation Processing Tool)
  • Common usages already covered. i.e. POJOs, builders

Testing

JUnit Params

https://github.com/Pragmatists/JUnitParams

  • Parameterize multiple methods with different arguments cardinality
  • Different data provider strategies

Mockito

http://mockito.org

  • Fluid DSL based on static methods
  • Provides support for Stubs, Mocks, and Spies
  • Mock interfaces, abstract classes, and concrete classes

Spock

Use JRuby

(Personal opinion): Too fancy to be real

Awaitility

https://github.com/awaitility/awaitility

Sounds unnecessary if the SUT is well DIed.