SlideShare a Scribd company logo
1 of 67
JAVA LIBRARIES
YOU CAN’T
AFFORD TO MISS
ANDRES ALMIRAY
@AALMIRAY
ANDRESALMIRAY.COM
@aalmiray
USE CASE
Write an application that consumes a REST
API.
Components must be small and reusable.
Say no to boilerplate code.
Behavior should be easy to test.
@aalmiray
THE LIBRARIES
PRODUCTION
Guice | Spring
OkHttp
Retrofit
JDeferred
RxJava | Reactor
MBassador
Lombok
Slf4j | Log4j2
TEST
JUnitParams
Mockito
Jukito
Awaitility
Spock
WireMock
@aalmiray
DISCLAIMER
@aalmiray
@aalmiray
@aalmiray
@aalmiray
USE CASE
Write an application that consumes a REST
API.
Components must be small and reusable.
Say no to boilerplate code.
Behavior should be easy to test.
@aalmiray
GITHUB API
Well documented REST API
Latest version located at
https://developer.github.com/v3/
We’re interested in the repositories
operation for now
@aalmiray
QUERYING REPOSITORIES
API described at
https://developer.github.com/v3/repos/#list-
organization-repositories
Given a query of the form
GET /orgs/${organization}/repos
@aalmiray
QUERY RESULT
[
{
"id": 1296269,
"owner": { /* omitted for brevity */ },
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"description": "This your first repo!",
"html_url": "https://github.com/octocat/Hello-World",
/* many other properties follow */
},
/* additional repositories if they exist */
]
@aalmiray
WHAT WE’LL NEED
Dependency Injection
HTTP client & REST behavior
JSON mapping
Boilerplate buster
Handle concurrency
@aalmiray
GET THE CODE
https://github.com/aalmiray/javatrove/
@aalmiray
DEPENDENCY
INJECTION
@aalmiray
public interface Github {
Promise<Collection<Repository>> repositories(String name);
}
@aalmiray
public class AppController {
@Inject private AppModel model;
@Inject private Github github;
public void loadRepositories() {
model.setState(RUNNING);
github.repositories(model.getOrganization())
.done(model.getRepositories()::addAll)
.fail(this::handleException)
.always((state, resolved, rejected) -> model.setState(READY));
}
}
@aalmiray
Guice - https://github.com/google/guice
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Github.class)
.to(GithubImpl.class)
.in(Singleton.class);
bind(AppModel.class)
.in(Singleton.class);
bind(GithubAPI.class)
.toProvider(GithubAPIProvider.class)
.in(Singleton.class);
// additional bindings …
}
});
@aalmiray
Guice - https://github.com/google/guice
• Reference implementation for JSR-330.
• Can bind types, instances, constant values.
• Can provide lazily evaluated instances, i.e, providers.
• Extensible lifecycle.
@aalmiray
BONUS
@aalmiray
Guava - https://github.com/google/guava
• New Collections:
• MultiSet
• BiMap
• MultiMap
• Table
• Utility classes for Collections
• Utility classes for String
• Caches
• Reflection
• I/O
• Functional programming support (JDK6+)
@aalmiray
Spring - http://projects.spring.io/spring-
framework
• More than just dependency injection
• Supports JSR-330
• Assertions
• MessageSource + MessageFormat
• Serialization
• JDBC, JPA
• JMX
• Validation
• Scheduling
• Testing
@aalmiray
REDUCING
BOILERPLATE
CODE
@aalmiray
Lombok - https://projectlombok.org
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;
import lombok.Setter;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Repository implements Comparable<Repository> {
private String name;
private String description;
@Setter(onMethod = @__({@JsonProperty("full_name")}))
private String fullName;
@Setter(onMethod = @__({@JsonProperty("html_url")}))
private String htmlUrl;
// continued
@aalmiray
Lombok - https://projectlombok.org
// continued
@Builder
public static Repository build(String name, String fullName, String
description, String htmlUrl) {
Repository repository = new Repository();
repository.name = name;
repository.fullName = fullName;
repository.description = description;
repository.htmlUrl = htmlUrl;
return repository;
}
}
@aalmiray
Lombok - https://projectlombok.org
public class ApplicationEvent {
}
@lombok.Data
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.ToString(callSuper = true)
public class NewInstanceEvent extends ApplicationEvent {
@javax.annotation.Nonnull
private final Object instance;
}
@aalmiray
Lombok - https://projectlombok.org
• Reduce boilerplate source code by generating bytecode.
• Relies on APT (Annotation Processing Tool).
• Extensible but not for the faint of heart.
• Common usages already covered, i.e, POJOs, builders.
• Don’t forget to enable annotation processing in your IDE!
@aalmiray
BEHAVIOR
@aalmiray
SLF4J - http://www.slf4j.org
• Wraps all other logging frameworks:
• java.util.logging
• Apache Commons Logging
• Apache Log4j
• Provides varargs methods
@aalmiray
HTTP
How many options are out there to build an
HTTP client?
How many ways are there to build a REST
client?
@aalmiray
OkHttp - http://square.github.io/okhttp
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
@aalmiray
OkHttp - http://square.github.io/okhttp
• Basic HTTP/HTTP2 Client API.
• Configuration is extensible via factory classes.
• HTTP lifecycle can be decorated via interceptors.
@aalmiray
ADDING JAVA ON TOP OF HTTP
What steps do we must ensure in order to
build an HTTP/REST client?
How should HTTP error codes be handled?
How to handle connection errors?
Parsing results in format X or Y.
@aalmiray
Retrofit - http://square.github.io/retrofit
public interface GithubAPI {
@GET("/orgs/{name}/repos")
Call<List<Repository>> repositories(@Path("name") String name);
@GET
Call<List<Repository>>> repositoriesPaginate(@Url String url);
}
@aalmiray
Retrofit - http://square.github.io/retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(
JacksonConverterFactory.create(objectMapper))
.build();
return retrofit.create(GithubAPI.class);
githubApi.repositories("foo");
@aalmiray
Retrofit - http://square.github.io/retrofit
• Wraps REST calls with Java interfaces.
• Extensible via factories.
• Relies on OkHttp.
@aalmiray
MULTI-THREADED CODE
The 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.
@aalmiray
JDeferred - http://jdeferred.org
public interface Github {
Promise<Collection<Repository>, Throwable, Void> repositories(String name);
}
@aalmiray
JDeferred - http://jdeferred.org
public class GithubImpl implements Github {
@Inject private GithubAPI api;
@Inject private DeferredManager deferredManager;
@Override
public Promise<Collection<Repository>, Throwable, Void> repositories(final
String name) {
return deferredManager.when(() -> {
Response<List<Repository>> response = api.repositories(name).execute();
if (response.isSuccess()) { return response.body(); }
throw new IllegalStateException(response.message());
});
}
}
@aalmiray
JDeferred - http://jdeferred.org
model.setState(RUNNING);
int limit = model.getLimit();
limit = limit > 0 ? limit : Integer.MAX_VALUE;
Promise<Collection<Repository>, Throwable, Repository> promise =
github.repositories(model.getOrganization(), limit);
promise.progress(model.getRepositories()::add)
.fail(Throwable::printStackTrace)
.always((state, resolved, rejected) -> model.setState(READY));
@aalmiray
JDeferred - http://jdeferred.org
• Delivers the concept of Promises
• Promises can be chained
• Java8 friendly, i.e, lambda expressions can be used
• One shot execution.
@aalmiray
REACTIVE PROGRAMMING
It’s time to embrace a new paradigm.
Reactive programming is a new name for
old and well-known concepts:
events and streams
@aalmiray
RxJava - http://reactivex.io
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(Schedulers.io())
.subscribe(
model.getRepositories()::add,
Throwable::printStackTrace);
model.setSubscription(subscription);
@aalmiray
Retrofit + RxJava
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);
}
@aalmiray
Retrofit + RxJava
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit.create(GithubAPI.class);
@aalmiray
Retrofit + RxJava
// concatenating multiple results into a single Observable
public Observable<Repository> repositories(String organization) {
requireNonNull(organization, "Argument 'organization' must not be blank");
return paginatedObservable(
() -> {
LOG.info("Querying /orgs/{}/repos", organization);
return api.repositories(organization);
},
(Links links) -> {
String next = links.next();
LOG.info("Querying {}", next);
return api.repositoriesPaginate(next);
});
}
@aalmiray
Retrofit + RxJava
// concatenating multiple results into a single Observable
private static <T> Observable<T> paginatedObservable(FirstPageSupplier<T>
firstPage, NextPageSupplier<T> nextPage) {
return processPage(nextPage, firstPage.get());
}
private static <T> Observable<T> processPage(NextPageSupplier<T> supplier,
Observable<Response<List<T>>> items) {
return items.flatMap(response -> {
Links links = Links.of(response.headers().get("Link"));
Observable<T> currentPage = Observable.from(response.body());
if (links.hasNext()) {
return currentPage.concatWith(processPage(supplier,
supplier.get(links)));
}
return currentPage;
});
}
@aalmiray
RxJava - http://reactivex.io
• Implements the Observable pattern.
• Delivers dozens of operations out of the box, e.g. zip, reduce,
concat.
• Supports backpressure, i.e, when the data producer is faster than
the data consumer.
@aalmiray
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?
@aalmiray
MBassador -
https://github.com/bennidi/mbassador
// event publishing
@Inject private ApplicationEventBus eventBus;
model.setSubscription(observable
.timeout(10, TimeUnit.SECONDS)
.doOnSubscribe(() -> model.setState(RUNNING))
.doOnTerminate(() -> model.setState(READY))
.doOnError(throwable -> eventBus.publishAsync(new ThrowableEvent(throwable)))
.subscribeOn(Schedulers.io())
.subscribe(model.getRepositories()::add));
@aalmiray
MBassador -
https://github.com/bennidi/mbassador
// event consuming
import net.engio.mbassy.listener.Handler;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
public class ApplicationEventHandler {
@Inject private ApplicationEventBus eventBus;
@PostConstruct private void init() { eventBus.subscribe(this); }
@PreDestroy private void destroy() { eventBus.unsubscribe(this); }
@Handler
public void handleThrowable(ThrowableEvent event) {
// handle event here !!
}
}
@aalmiray
MBassador -
https://github.com/bennidi/mbassador
• Configurable event bus based on annotations.
• Faster implementation than Guava’s event bus.
• https://github.com/bennidi/eventbus-performance
• NOTE: project is no longer actively maintained, fixes and features will
be slow to come.
@aalmiray
TESTING
@aalmiray
JUnitParams -
https://github.com/Pragmatists/JUnitParams
@RunWith(JUnitParamsRunner.class)
public class SampleServiceTest {
@Test
@Parameters({",Howdy stranger!",
"Test, Hello Test"})
public void sayHello(String input, String output) {
// given:
SampleService service = new SampleService();
// expect:
assertThat(service.sayHello(input), equalTo(output));
}
}
@aalmiray
JUnitParams -
https://github.com/Pragmatists/JUnitParams
• Parameterize multiple methods with different argument
cardinality.
• Different data provider strategies.
@aalmiray
Mockito - http://mockito.org
@Test @Parameters({",Howdy stranger!", "Test, Hello Test"})
public void sayHelloAction(String input, String output) {
// given:
SampleController controller = new SampleController();
controller.setModel(new SampleModel());
controller.setService(mock(SampleService.class));
// expectations
when(controller.getService().sayHello(input)).thenReturn(output);
// when:
controller.getModel().setInput(input);
controller.sayHello();
// then:
assertThat(controller.getModel().getOutput(), equalTo(output));
verify(controller.getService(), only()).sayHello(input);
}
@aalmiray
Mockito - http://mockito.org
• Fluid DSL based on static methods.
• Provides support for Stubs, Mocks, and Spies.
• Mock interfaces, abstract classes, and concrete classes.
@aalmiray
Jukito - https://github.com/ArcBees/Jukito
@RunWith(JukitoRunner.class)
public class SampleControllerJukitoTest {
@Inject private SampleController controller;
@Before
public void setupMocks(SampleService sampleService) {
when(sampleService.sayHello("Test")).thenReturn("Hello Test");
}
@Test
public void sayHelloAction() {
controller.setModel(new SampleModel());
controller.getModel().setInput("Test");
controller.sayHello();
assertThat(controller.getModel().getOutput(),
equalTo("Hello Test"));
verify(controller.getService(), only()).sayHello("Test");
}
}
@aalmiray
Jukito - https://github.com/ArcBees/Jukito
• Combines JUnit, Guice, and Mockito
• Bind multiple values to the same source type.
• Can be used to parameterize test methods.
@aalmiray
Spock- http://spockframework.org
@spock.lang.Unroll
class SampleControllerSpec extends spock.lang.Specification {
def "Invoke say hello with #input results in #output"() {
given:
SampleController controller = new SampleController()
controller.model = new SampleModel()
controller.service = Mock(SampleService) {
sayHello(input) >> output
}
when:
controller.model.input = input
controller.sayHello()
then:
controller.model.output == output
where:
input << ['', 'Test']
output << ['Howdy, stranger!', 'Hello Test']
}
}
@aalmiray
Spock- http://spockframework.org
• Groovy based DSL.
• Parameterize multiple methods with different argument
cardinality.
• Parameterize test method names.
• JUnit friendly (can use extensions and rules).
@aalmiray
Awaitility -
https://github.com/awaitility/awaitility
@Test
public void happyPath(Github github) {
// given:
Collection<Repository> repositories = createSampleRepositories();
when(github.repositories(ORGANIZATION))
.thenReturn(Observable.from(repositories));
// when:
model.setOrganization(ORGANIZATION);
controller.load();
await().timeout(2, SECONDS).until(model::getState, equalTo(State.READY));
// then:
assertThat(model.getRepositories(), hasSize(10));
assertThat(model.getRepositories(), equalTo(repositories));
verify(github, only()).repositories(ORGANIZATION);
}
@aalmiray
Awaitility -
https://github.com/awaitility/awaitility
• DSL for testing multi-threaded code.
• Extensions available for Java8, Groovy, and Scala.
• Conditions can be customized with Hamcrest matchers.
@aalmiray
WireMock- http://wiremock.org/
import static com.github.tomakehurst.wiremock.client.WireMock.*;
String nextUrl = "/organizations/1/repos?page=2";
List<Repository> repositories = createSampleRepositories();
stubFor(get(urlEqualTo("/orgs/" + ORGANIZATION + "/repos"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/json")
.withHeader("Link", "<http://localhost:8080" + nextUrl + ">; rel="next"")
.withBody(repositoriesAsJSON(repositories.subList(0, 5), objectMapper))));
stubFor(get(urlEqualTo(nextUrl ))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/json")
.withBody(repositoriesAsJSON(repositories.subList(5, 10), objectMapper))));
@aalmiray
WireMock- http://wiremock.org/
• Supply custom HTTP response payloads.
• DSL for matching HTTP requests.
• Supports record and playback.
@aalmiray
@aalmiray
HTTP://ANDRESALMIRAY.COM/NEWSLETTER
HTTP://ANDRESALMIRAY.COM/EDITORIAL
THANK YOU!
ANDRES ALMIRAY
@AALMIRAY
ANDRESALMIRAY.COM

More Related Content

What's hot

Retrofit
RetrofitRetrofit
Retrofitbresiu
 
Rxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaRxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaKros Huang
 
Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Daniele Pallastrelli
 
Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Loiane Groner
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaFabio Collini
 
Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.jsMatthew Beale
 
Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹Kros Huang
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaKasun Indrasiri
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfLoiane Groner
 
Dev Day 2019: Mike Sperber – Software Design für die Seele
Dev Day 2019: Mike Sperber – Software Design für die SeeleDev Day 2019: Mike Sperber – Software Design für die Seele
Dev Day 2019: Mike Sperber – Software Design für die SeeleDevDay Dresden
 
Real world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programmingEric Polerecky
 
Dependency Injection with CDI in 15 minutes
Dependency Injection with CDI in 15 minutesDependency Injection with CDI in 15 minutes
Dependency Injection with CDI in 15 minutesAntonio Goncalves
 
Gerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRxGerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRxLoiane Groner
 
React table tutorial use filter (part 2)
React table tutorial use filter (part 2)React table tutorial use filter (part 2)
React table tutorial use filter (part 2)Katy Slemon
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesHaim Yadid
 

What's hot (20)

Retrofit
RetrofitRetrofit
Retrofit
 
Rxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaRxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJava
 
Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++Going native with less coupling: Dependency Injection in C++
Going native with less coupling: Dependency Injection in C++
 
Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018Angular for Java Enterprise Developers: Oracle Code One 2018
Angular for Java Enterprise Developers: Oracle Code One 2018
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
Containers & Dependency in Ember.js
Containers & Dependency in Ember.jsContainers & Dependency in Ember.js
Containers & Dependency in Ember.js
 
Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹
 
Reactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-JavaReactive Programming in Java 8 with Rx-Java
Reactive Programming in Java 8 with Rx-Java
 
Spring AOP
Spring AOPSpring AOP
Spring AOP
 
Jasmine BDD for Javascript
Jasmine BDD for JavascriptJasmine BDD for Javascript
Jasmine BDD for Javascript
 
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConfFull-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
Full-Stack Reativo com Spring WebFlux + Angular - FiqueEmCasaConf
 
Dev Day 2019: Mike Sperber – Software Design für die Seele
Dev Day 2019: Mike Sperber – Software Design für die SeeleDev Day 2019: Mike Sperber – Software Design für die Seele
Dev Day 2019: Mike Sperber – Software Design für die Seele
 
Real world functional reactive programming
Real world functional reactive programmingReal world functional reactive programming
Real world functional reactive programming
 
Reactive Java (33rd Degree)
Reactive Java (33rd Degree)Reactive Java (33rd Degree)
Reactive Java (33rd Degree)
 
Dependency Injection with CDI in 15 minutes
Dependency Injection with CDI in 15 minutesDependency Injection with CDI in 15 minutes
Dependency Injection with CDI in 15 minutes
 
Gerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRxGerenciamento de estado no Angular com NgRx
Gerenciamento de estado no Angular com NgRx
 
Completable future
Completable futureCompletable future
Completable future
 
React table tutorial use filter (part 2)
React table tutorial use filter (part 2)React table tutorial use filter (part 2)
React table tutorial use filter (part 2)
 
The Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFuturesThe Future of Futures - A Talk About Java 8 CompletableFutures
The Future of Futures - A Talk About Java 8 CompletableFutures
 
CDI: How do I ?
CDI: How do I ?CDI: How do I ?
CDI: How do I ?
 

Similar to Java Libraries You Can't Afford to Miss

Java Libraries You Can't Afford To Miss
Java Libraries You Can't Afford To MissJava Libraries You Can't Afford To Miss
Java Libraries You Can't Afford To MissAndres Almiray
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissAndres Almiray
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Andres Almiray
 
Annotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark ArtsAnnotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark ArtsJames Kirkbride
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive ProgrammingAndres Almiray
 
Building maintainable javascript applications
Building maintainable javascript applicationsBuilding maintainable javascript applications
Building maintainable javascript applicationsequisodie
 
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineGoogle Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineRoman Kirillov
 
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...Guillaume Laforge
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James NelsonGWTcon
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
The new and smart way to build microservices - Eclipse MicroProfile
The new and smart way to build microservices - Eclipse MicroProfileThe new and smart way to build microservices - Eclipse MicroProfile
The new and smart way to build microservices - Eclipse MicroProfileEmily Jiang
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Jesus Manuel Olivas
 
Plugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsPlugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsSadayuki Furuhashi
 
Maintaining a dependency graph with weaver
Maintaining a dependency graph with weaverMaintaining a dependency graph with weaver
Maintaining a dependency graph with weaverScribd
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Mastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonMastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonAEM HUB
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling RewriterJustin Edelson
 
Try using Aeromock by Marverick, Inc.
Try using Aeromock by Marverick, Inc.Try using Aeromock by Marverick, Inc.
Try using Aeromock by Marverick, Inc.scalaconfjp
 

Similar to Java Libraries You Can't Afford to Miss (20)

Java Libraries You Can't Afford To Miss
Java Libraries You Can't Afford To MissJava Libraries You Can't Afford To Miss
Java Libraries You Can't Afford To Miss
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to MissJava Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
Annotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark ArtsAnnotation Processing - Demystifying Java's Dark Arts
Annotation Processing - Demystifying Java's Dark Arts
 
Understanding Reactive Programming
Understanding Reactive ProgrammingUnderstanding Reactive Programming
Understanding Reactive Programming
 
Building maintainable javascript applications
Building maintainable javascript applicationsBuilding maintainable javascript applications
Building maintainable javascript applications
 
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngineGoogle Cloud Endpoints: Building Third-Party APIs on Google AppEngine
Google Cloud Endpoints: Building Third-Party APIs on Google AppEngine
 
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson
 
Designing Better API
Designing Better APIDesigning Better API
Designing Better API
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
The new and smart way to build microservices - Eclipse MicroProfile
The new and smart way to build microservices - Eclipse MicroProfileThe new and smart way to build microservices - Eclipse MicroProfile
The new and smart way to build microservices - Eclipse MicroProfile
 
Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...Creating a modern web application using Symfony API Platform, ReactJS and Red...
Creating a modern web application using Symfony API Platform, ReactJS and Red...
 
Plugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGemsPlugin-based software design with Ruby and RubyGems
Plugin-based software design with Ruby and RubyGems
 
Maintaining a dependency graph with weaver
Maintaining a dependency graph with weaverMaintaining a dependency graph with weaver
Maintaining a dependency graph with weaver
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Mastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin EdelsonMastering the Sling Rewriter by Justin Edelson
Mastering the Sling Rewriter by Justin Edelson
 
Mastering the Sling Rewriter
Mastering the Sling RewriterMastering the Sling Rewriter
Mastering the Sling Rewriter
 
Try using Aeromock by Marverick, Inc.
Try using Aeromock by Marverick, Inc.Try using Aeromock by Marverick, Inc.
Try using Aeromock by Marverick, Inc.
 

More from Andres Almiray

Creando, creciendo, y manteniendo una comunidad de codigo abierto
Creando, creciendo, y manteniendo una comunidad de codigo abiertoCreando, creciendo, y manteniendo una comunidad de codigo abierto
Creando, creciendo, y manteniendo una comunidad de codigo abiertoAndres Almiray
 
Liberando a produccion con confianza
Liberando a produccion con confianzaLiberando a produccion con confianza
Liberando a produccion con confianzaAndres Almiray
 
Liberando a produccion con confidencia
Liberando a produccion con confidenciaLiberando a produccion con confidencia
Liberando a produccion con confidenciaAndres Almiray
 
OracleDB Ecosystem for Java Developers
OracleDB Ecosystem for Java DevelopersOracleDB Ecosystem for Java Developers
OracleDB Ecosystem for Java DevelopersAndres Almiray
 
Softcon.ph - Maven Puzzlers
Softcon.ph - Maven PuzzlersSoftcon.ph - Maven Puzzlers
Softcon.ph - Maven PuzzlersAndres Almiray
 
Oracle Database Ecosystem for Java Developers
Oracle Database Ecosystem for Java DevelopersOracle Database Ecosystem for Java Developers
Oracle Database Ecosystem for Java DevelopersAndres Almiray
 
JReleaser - Releasing at the speed of light
JReleaser - Releasing at the speed of lightJReleaser - Releasing at the speed of light
JReleaser - Releasing at the speed of lightAndres Almiray
 
Building modular applications with the Java Platform Module System and Layrry
Building modular applications with the Java Platform Module System and LayrryBuilding modular applications with the Java Platform Module System and Layrry
Building modular applications with the Java Platform Module System and LayrryAndres Almiray
 
Going Reactive with g rpc
Going Reactive with g rpcGoing Reactive with g rpc
Going Reactive with g rpcAndres Almiray
 
Building modular applications with JPMS and Layrry
Building modular applications with JPMS and LayrryBuilding modular applications with JPMS and Layrry
Building modular applications with JPMS and LayrryAndres Almiray
 
Taking Micronaut out for a spin
Taking Micronaut out for a spinTaking Micronaut out for a spin
Taking Micronaut out for a spinAndres Almiray
 
Apache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and YouApache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and YouAndres Almiray
 
What I wish I knew about Maven years ago
What I wish I knew about Maven years agoWhat I wish I knew about Maven years ago
What I wish I knew about Maven years agoAndres Almiray
 
What I wish I knew about maven years ago
What I wish I knew about maven years agoWhat I wish I knew about maven years ago
What I wish I knew about maven years agoAndres Almiray
 
The impact of sci fi in tech
The impact of sci fi in techThe impact of sci fi in tech
The impact of sci fi in techAndres Almiray
 
Gradle Ex Machina - Devoxx 2019
Gradle Ex Machina - Devoxx 2019Gradle Ex Machina - Devoxx 2019
Gradle Ex Machina - Devoxx 2019Andres Almiray
 
Creating Better Builds with Gradle
Creating Better Builds with GradleCreating Better Builds with Gradle
Creating Better Builds with GradleAndres Almiray
 
Interacting with the Oracle Cloud Java SDK with Gradle
Interacting with the Oracle Cloud Java SDK with GradleInteracting with the Oracle Cloud Java SDK with Gradle
Interacting with the Oracle Cloud Java SDK with GradleAndres Almiray
 

More from Andres Almiray (20)

Creando, creciendo, y manteniendo una comunidad de codigo abierto
Creando, creciendo, y manteniendo una comunidad de codigo abiertoCreando, creciendo, y manteniendo una comunidad de codigo abierto
Creando, creciendo, y manteniendo una comunidad de codigo abierto
 
Liberando a produccion con confianza
Liberando a produccion con confianzaLiberando a produccion con confianza
Liberando a produccion con confianza
 
Liberando a produccion con confidencia
Liberando a produccion con confidenciaLiberando a produccion con confidencia
Liberando a produccion con confidencia
 
OracleDB Ecosystem for Java Developers
OracleDB Ecosystem for Java DevelopersOracleDB Ecosystem for Java Developers
OracleDB Ecosystem for Java Developers
 
Softcon.ph - Maven Puzzlers
Softcon.ph - Maven PuzzlersSoftcon.ph - Maven Puzzlers
Softcon.ph - Maven Puzzlers
 
Maven Puzzlers
Maven PuzzlersMaven Puzzlers
Maven Puzzlers
 
Oracle Database Ecosystem for Java Developers
Oracle Database Ecosystem for Java DevelopersOracle Database Ecosystem for Java Developers
Oracle Database Ecosystem for Java Developers
 
JReleaser - Releasing at the speed of light
JReleaser - Releasing at the speed of lightJReleaser - Releasing at the speed of light
JReleaser - Releasing at the speed of light
 
Building modular applications with the Java Platform Module System and Layrry
Building modular applications with the Java Platform Module System and LayrryBuilding modular applications with the Java Platform Module System and Layrry
Building modular applications with the Java Platform Module System and Layrry
 
Going Reactive with g rpc
Going Reactive with g rpcGoing Reactive with g rpc
Going Reactive with g rpc
 
Building modular applications with JPMS and Layrry
Building modular applications with JPMS and LayrryBuilding modular applications with JPMS and Layrry
Building modular applications with JPMS and Layrry
 
Taking Micronaut out for a spin
Taking Micronaut out for a spinTaking Micronaut out for a spin
Taking Micronaut out for a spin
 
Apache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and YouApache Groovy's Metaprogramming Options and You
Apache Groovy's Metaprogramming Options and You
 
What I wish I knew about Maven years ago
What I wish I knew about Maven years agoWhat I wish I knew about Maven years ago
What I wish I knew about Maven years ago
 
What I wish I knew about maven years ago
What I wish I knew about maven years agoWhat I wish I knew about maven years ago
What I wish I knew about maven years ago
 
The impact of sci fi in tech
The impact of sci fi in techThe impact of sci fi in tech
The impact of sci fi in tech
 
Gradle Ex Machina - Devoxx 2019
Gradle Ex Machina - Devoxx 2019Gradle Ex Machina - Devoxx 2019
Gradle Ex Machina - Devoxx 2019
 
Creating Better Builds with Gradle
Creating Better Builds with GradleCreating Better Builds with Gradle
Creating Better Builds with Gradle
 
Interacting with the Oracle Cloud Java SDK with Gradle
Interacting with the Oracle Cloud Java SDK with GradleInteracting with the Oracle Cloud Java SDK with Gradle
Interacting with the Oracle Cloud Java SDK with Gradle
 
Gradle ex-machina
Gradle ex-machinaGradle ex-machina
Gradle ex-machina
 

Recently uploaded

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

Java Libraries You Can't Afford to Miss

  • 1. JAVA LIBRARIES YOU CAN’T AFFORD TO MISS ANDRES ALMIRAY @AALMIRAY ANDRESALMIRAY.COM
  • 2. @aalmiray USE CASE Write an application that consumes a REST API. Components must be small and reusable. Say no to boilerplate code. Behavior should be easy to test.
  • 3. @aalmiray THE LIBRARIES PRODUCTION Guice | Spring OkHttp Retrofit JDeferred RxJava | Reactor MBassador Lombok Slf4j | Log4j2 TEST JUnitParams Mockito Jukito Awaitility Spock WireMock
  • 8. @aalmiray USE CASE Write an application that consumes a REST API. Components must be small and reusable. Say no to boilerplate code. Behavior should be easy to test.
  • 9. @aalmiray GITHUB API Well documented REST API Latest version located at https://developer.github.com/v3/ We’re interested in the repositories operation for now
  • 10. @aalmiray QUERYING REPOSITORIES API described at https://developer.github.com/v3/repos/#list- organization-repositories Given a query of the form GET /orgs/${organization}/repos
  • 11. @aalmiray QUERY RESULT [ { "id": 1296269, "owner": { /* omitted for brevity */ }, "name": "Hello-World", "full_name": "octocat/Hello-World", "description": "This your first repo!", "html_url": "https://github.com/octocat/Hello-World", /* many other properties follow */ }, /* additional repositories if they exist */ ]
  • 12. @aalmiray WHAT WE’LL NEED Dependency Injection HTTP client & REST behavior JSON mapping Boilerplate buster Handle concurrency
  • 15. @aalmiray public interface Github { Promise<Collection<Repository>> repositories(String name); }
  • 16. @aalmiray public class AppController { @Inject private AppModel model; @Inject private Github github; public void loadRepositories() { model.setState(RUNNING); github.repositories(model.getOrganization()) .done(model.getRepositories()::addAll) .fail(this::handleException) .always((state, resolved, rejected) -> model.setState(READY)); } }
  • 17. @aalmiray Guice - https://github.com/google/guice Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { bind(Github.class) .to(GithubImpl.class) .in(Singleton.class); bind(AppModel.class) .in(Singleton.class); bind(GithubAPI.class) .toProvider(GithubAPIProvider.class) .in(Singleton.class); // additional bindings … } });
  • 18. @aalmiray Guice - https://github.com/google/guice • Reference implementation for JSR-330. • Can bind types, instances, constant values. • Can provide lazily evaluated instances, i.e, providers. • Extensible lifecycle.
  • 20. @aalmiray Guava - https://github.com/google/guava • New Collections: • MultiSet • BiMap • MultiMap • Table • Utility classes for Collections • Utility classes for String • Caches • Reflection • I/O • Functional programming support (JDK6+)
  • 21. @aalmiray Spring - http://projects.spring.io/spring- framework • More than just dependency injection • Supports JSR-330 • Assertions • MessageSource + MessageFormat • Serialization • JDBC, JPA • JMX • Validation • Scheduling • Testing
  • 23. @aalmiray Lombok - https://projectlombok.org import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Data; import lombok.Setter; @Data @JsonIgnoreProperties(ignoreUnknown = true) public class Repository implements Comparable<Repository> { private String name; private String description; @Setter(onMethod = @__({@JsonProperty("full_name")})) private String fullName; @Setter(onMethod = @__({@JsonProperty("html_url")})) private String htmlUrl; // continued
  • 24. @aalmiray Lombok - https://projectlombok.org // continued @Builder public static Repository build(String name, String fullName, String description, String htmlUrl) { Repository repository = new Repository(); repository.name = name; repository.fullName = fullName; repository.description = description; repository.htmlUrl = htmlUrl; return repository; } }
  • 25. @aalmiray Lombok - https://projectlombok.org public class ApplicationEvent { } @lombok.Data @lombok.EqualsAndHashCode(callSuper = true) @lombok.ToString(callSuper = true) public class NewInstanceEvent extends ApplicationEvent { @javax.annotation.Nonnull private final Object instance; }
  • 26. @aalmiray Lombok - https://projectlombok.org • Reduce boilerplate source code by generating bytecode. • Relies on APT (Annotation Processing Tool). • Extensible but not for the faint of heart. • Common usages already covered, i.e, POJOs, builders. • Don’t forget to enable annotation processing in your IDE!
  • 28. @aalmiray SLF4J - http://www.slf4j.org • Wraps all other logging frameworks: • java.util.logging • Apache Commons Logging • Apache Log4j • Provides varargs methods
  • 29. @aalmiray HTTP How many options are out there to build an HTTP client? How many ways are there to build a REST client?
  • 30. @aalmiray OkHttp - http://square.github.io/okhttp public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string(); }
  • 31. @aalmiray OkHttp - http://square.github.io/okhttp • Basic HTTP/HTTP2 Client API. • Configuration is extensible via factory classes. • HTTP lifecycle can be decorated via interceptors.
  • 32. @aalmiray ADDING JAVA ON TOP OF HTTP What steps do we must ensure in order to build an HTTP/REST client? How should HTTP error codes be handled? How to handle connection errors? Parsing results in format X or Y.
  • 33. @aalmiray Retrofit - http://square.github.io/retrofit public interface GithubAPI { @GET("/orgs/{name}/repos") Call<List<Repository>> repositories(@Path("name") String name); @GET Call<List<Repository>>> repositoriesPaginate(@Url String url); }
  • 34. @aalmiray Retrofit - http://square.github.io/retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory( JacksonConverterFactory.create(objectMapper)) .build(); return retrofit.create(GithubAPI.class); githubApi.repositories("foo");
  • 35. @aalmiray Retrofit - http://square.github.io/retrofit • Wraps REST calls with Java interfaces. • Extensible via factories. • Relies on OkHttp.
  • 36. @aalmiray MULTI-THREADED CODE The 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.
  • 37. @aalmiray JDeferred - http://jdeferred.org public interface Github { Promise<Collection<Repository>, Throwable, Void> repositories(String name); }
  • 38. @aalmiray JDeferred - http://jdeferred.org public class GithubImpl implements Github { @Inject private GithubAPI api; @Inject private DeferredManager deferredManager; @Override public Promise<Collection<Repository>, Throwable, Void> repositories(final String name) { return deferredManager.when(() -> { Response<List<Repository>> response = api.repositories(name).execute(); if (response.isSuccess()) { return response.body(); } throw new IllegalStateException(response.message()); }); } }
  • 39. @aalmiray JDeferred - http://jdeferred.org model.setState(RUNNING); int limit = model.getLimit(); limit = limit > 0 ? limit : Integer.MAX_VALUE; Promise<Collection<Repository>, Throwable, Repository> promise = github.repositories(model.getOrganization(), limit); promise.progress(model.getRepositories()::add) .fail(Throwable::printStackTrace) .always((state, resolved, rejected) -> model.setState(READY));
  • 40. @aalmiray JDeferred - http://jdeferred.org • Delivers the concept of Promises • Promises can be chained • Java8 friendly, i.e, lambda expressions can be used • One shot execution.
  • 41. @aalmiray REACTIVE PROGRAMMING It’s time to embrace a new paradigm. Reactive programming is a new name for old and well-known concepts: events and streams
  • 42. @aalmiray RxJava - http://reactivex.io 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(Schedulers.io()) .subscribe( model.getRepositories()::add, Throwable::printStackTrace); model.setSubscription(subscription);
  • 43. @aalmiray Retrofit + RxJava 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); }
  • 44. @aalmiray Retrofit + RxJava Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(JacksonConverterFactory.create(objectMapper)) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); return retrofit.create(GithubAPI.class);
  • 45. @aalmiray Retrofit + RxJava // concatenating multiple results into a single Observable public Observable<Repository> repositories(String organization) { requireNonNull(organization, "Argument 'organization' must not be blank"); return paginatedObservable( () -> { LOG.info("Querying /orgs/{}/repos", organization); return api.repositories(organization); }, (Links links) -> { String next = links.next(); LOG.info("Querying {}", next); return api.repositoriesPaginate(next); }); }
  • 46. @aalmiray Retrofit + RxJava // concatenating multiple results into a single Observable private static <T> Observable<T> paginatedObservable(FirstPageSupplier<T> firstPage, NextPageSupplier<T> nextPage) { return processPage(nextPage, firstPage.get()); } private static <T> Observable<T> processPage(NextPageSupplier<T> supplier, Observable<Response<List<T>>> items) { return items.flatMap(response -> { Links links = Links.of(response.headers().get("Link")); Observable<T> currentPage = Observable.from(response.body()); if (links.hasNext()) { return currentPage.concatWith(processPage(supplier, supplier.get(links))); } return currentPage; }); }
  • 47. @aalmiray RxJava - http://reactivex.io • Implements the Observable pattern. • Delivers dozens of operations out of the box, e.g. zip, reduce, concat. • Supports backpressure, i.e, when the data producer is faster than the data consumer.
  • 48. @aalmiray 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?
  • 49. @aalmiray MBassador - https://github.com/bennidi/mbassador // event publishing @Inject private ApplicationEventBus eventBus; model.setSubscription(observable .timeout(10, TimeUnit.SECONDS) .doOnSubscribe(() -> model.setState(RUNNING)) .doOnTerminate(() -> model.setState(READY)) .doOnError(throwable -> eventBus.publishAsync(new ThrowableEvent(throwable))) .subscribeOn(Schedulers.io()) .subscribe(model.getRepositories()::add));
  • 50. @aalmiray MBassador - https://github.com/bennidi/mbassador // event consuming import net.engio.mbassy.listener.Handler; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; public class ApplicationEventHandler { @Inject private ApplicationEventBus eventBus; @PostConstruct private void init() { eventBus.subscribe(this); } @PreDestroy private void destroy() { eventBus.unsubscribe(this); } @Handler public void handleThrowable(ThrowableEvent event) { // handle event here !! } }
  • 51. @aalmiray MBassador - https://github.com/bennidi/mbassador • Configurable event bus based on annotations. • Faster implementation than Guava’s event bus. • https://github.com/bennidi/eventbus-performance • NOTE: project is no longer actively maintained, fixes and features will be slow to come.
  • 53. @aalmiray JUnitParams - https://github.com/Pragmatists/JUnitParams @RunWith(JUnitParamsRunner.class) public class SampleServiceTest { @Test @Parameters({",Howdy stranger!", "Test, Hello Test"}) public void sayHello(String input, String output) { // given: SampleService service = new SampleService(); // expect: assertThat(service.sayHello(input), equalTo(output)); } }
  • 54. @aalmiray JUnitParams - https://github.com/Pragmatists/JUnitParams • Parameterize multiple methods with different argument cardinality. • Different data provider strategies.
  • 55. @aalmiray Mockito - http://mockito.org @Test @Parameters({",Howdy stranger!", "Test, Hello Test"}) public void sayHelloAction(String input, String output) { // given: SampleController controller = new SampleController(); controller.setModel(new SampleModel()); controller.setService(mock(SampleService.class)); // expectations when(controller.getService().sayHello(input)).thenReturn(output); // when: controller.getModel().setInput(input); controller.sayHello(); // then: assertThat(controller.getModel().getOutput(), equalTo(output)); verify(controller.getService(), only()).sayHello(input); }
  • 56. @aalmiray Mockito - http://mockito.org • Fluid DSL based on static methods. • Provides support for Stubs, Mocks, and Spies. • Mock interfaces, abstract classes, and concrete classes.
  • 57. @aalmiray Jukito - https://github.com/ArcBees/Jukito @RunWith(JukitoRunner.class) public class SampleControllerJukitoTest { @Inject private SampleController controller; @Before public void setupMocks(SampleService sampleService) { when(sampleService.sayHello("Test")).thenReturn("Hello Test"); } @Test public void sayHelloAction() { controller.setModel(new SampleModel()); controller.getModel().setInput("Test"); controller.sayHello(); assertThat(controller.getModel().getOutput(), equalTo("Hello Test")); verify(controller.getService(), only()).sayHello("Test"); } }
  • 58. @aalmiray Jukito - https://github.com/ArcBees/Jukito • Combines JUnit, Guice, and Mockito • Bind multiple values to the same source type. • Can be used to parameterize test methods.
  • 59. @aalmiray Spock- http://spockframework.org @spock.lang.Unroll class SampleControllerSpec extends spock.lang.Specification { def "Invoke say hello with #input results in #output"() { given: SampleController controller = new SampleController() controller.model = new SampleModel() controller.service = Mock(SampleService) { sayHello(input) >> output } when: controller.model.input = input controller.sayHello() then: controller.model.output == output where: input << ['', 'Test'] output << ['Howdy, stranger!', 'Hello Test'] } }
  • 60. @aalmiray Spock- http://spockframework.org • Groovy based DSL. • Parameterize multiple methods with different argument cardinality. • Parameterize test method names. • JUnit friendly (can use extensions and rules).
  • 61. @aalmiray Awaitility - https://github.com/awaitility/awaitility @Test public void happyPath(Github github) { // given: Collection<Repository> repositories = createSampleRepositories(); when(github.repositories(ORGANIZATION)) .thenReturn(Observable.from(repositories)); // when: model.setOrganization(ORGANIZATION); controller.load(); await().timeout(2, SECONDS).until(model::getState, equalTo(State.READY)); // then: assertThat(model.getRepositories(), hasSize(10)); assertThat(model.getRepositories(), equalTo(repositories)); verify(github, only()).repositories(ORGANIZATION); }
  • 62. @aalmiray Awaitility - https://github.com/awaitility/awaitility • DSL for testing multi-threaded code. • Extensions available for Java8, Groovy, and Scala. • Conditions can be customized with Hamcrest matchers.
  • 63. @aalmiray WireMock- http://wiremock.org/ import static com.github.tomakehurst.wiremock.client.WireMock.*; String nextUrl = "/organizations/1/repos?page=2"; List<Repository> repositories = createSampleRepositories(); stubFor(get(urlEqualTo("/orgs/" + ORGANIZATION + "/repos")) .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "text/json") .withHeader("Link", "<http://localhost:8080" + nextUrl + ">; rel="next"") .withBody(repositoriesAsJSON(repositories.subList(0, 5), objectMapper)))); stubFor(get(urlEqualTo(nextUrl )) .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "text/json") .withBody(repositoriesAsJSON(repositories.subList(5, 10), objectMapper))));
  • 64. @aalmiray WireMock- http://wiremock.org/ • Supply custom HTTP response payloads. • DSL for matching HTTP requests. • Supports record and playback.

Editor's Notes

  1. LICENSE