REST with Asynchronous Jersey and RXJava – Part 1

By | November 19, 2016

In this series of articles I will implement a RESTful web service using Spring Boot and Jersey. I will then modify the service as to use asynchronous server-side request processing and RXJava. Load-tests will be made using Gatling before and after the modifications, in order to determine any improvements.

 Note:
The example program in this article does not implement HATEOAS. HATEOAS, while it may be an essential part of RESTful web services, is not important to what I want to show in this article. If you think I commit heresy by calling my service a RESTful web service then please add a mental filter that replaces all occurrences of “REST” with “JSON over HTTP” or stop reading.

The example program in this article is available on GitHub; the “before” branch is the version without asynchronous Jersey and RXJava, the master branch is the version with the both technologies applied.

With that said, let’s get started with the first part in which the basic implementation of the RESTful web service is implemented using Spring Boot and Jersey (JAX-RS).

Operators of the REST service. Photo by Colin M.L. Burnett.

Operator of the REST service or the author of this article after a long coding session. Photo by Colin M.L. Burnett. CC-BY-2.0.

Architecture of the Example Service

The example service consists of four types of classes; domain classes (entities), repositories, services and REST adapters. Each of the four types of classes are stored in a package of their own. The dependencies between the packages are shown in the following diagram:

Package diagram of the example service to be developed in this article.

Package diagram of the example service to be developed in this article.

Thus repositories have dependencies only to the domain, services have dependencies to the repositories and the domain and finally restadapters have dependencies to services and the domain.

The choice of frameworks etc are:

  • Spring 5
    As of writing this article, Spring 5 has not been released yet.
  • Spring Boot 2
    I chose Spring Boot for the development speed.
    As with Spring 5, not released yet.
  • RxJava 2
    Version 2 was just released and I wanted to use the newer RxJava in order to avoid having to re-learn.
  • Jersey (JAX-RS implementation)
    I have worked more with Jersey and like it better than Spring MVC for REST services. In addition I wanted to try out asynchronous request handling with Jersey.
  • Spring Data JPA
    Again, something I have worked with and which I like. I don’t see myself working with JPA without using Spring Data JPA, given the zero-code repositories.
    In addition, customizing the behaviour of Spring Data JPA repositories is fairly easy, as we will see in this article.

Choices related to testing:

  • TestNG
    Very good testing framework that really shines in the area of multi-threaded tests. Alas, no multi-threaded tests implemented in this article, but I do expect them in a close future.
  • RestAssured
    Another very nice testing framework. This one is for testing REST web services. As of writing this article, version 3 has just been released.
  • Unitils Reflection Assert
    This testing-framework implements comparing two objects using reflection. Finally no more code that compares the state of two objects!

Create the Project

The example project was created using Spring Initializr; either in IntelliJ IDEA, your favourite IDE or on the Spring Initializr web-page. I used the following parameters on the Spring Initializr web-page:

Generate a Maven Project with Spring Boot 2.0.0 (SNAPSHOT).

Parameter Value
Group se.ivankrizsan.restexample
Artifact rest-example
Name rest-example
Description REST example with Jersey and RXJava
Package Name se.ivankrizsan.restexample
Packaging Jar
Java Version 1.8
Language Java

Dependencies:

  • Jersey (JAX-RS)
  • JPA
  • HSQLDB

Here is the URL to generate the project using Spring Initializr.

Modify the new project’s pom.xml file to look like this:

We are now ready to start implementing the example project.

Entity Classes

The domain model consists of the classes shown in this class diagram:

Entities in the example program.

Entities in the example program.

Nothing fancy in these classes, since the focus of the example program is on storing and retrieving these entities and not on their behaviour.

Entity Base Class

In addition to the above domain classes, I have used an abstract base class that implements the common properties of an entity which have a long integer id. This base class is implemented like this:

Nothing special about this class. The equals and hashCode methods were generated by the IDE. The reason for implementing this entity base class is, as will be shown later, to be able to create common base classes for services and REST resources.

Shape Class

The Shape class is an abstract entity class that will serve as parent-class for circle and rectangle entities. I find it interesting because it shows how to handle persistence and JSON marshalling and unmarshalling of entity-classes that has a common ancestor.

Note that:

  • The inheritance strategy is to create one table per concrete subclass of the Shape class.
    Thus there will be one table for circles and another for rectangles.
  • In order to be able to re-create an object of the appropriate type when unmarshalling JSON representation, I had to include the @JsonTypeInfo annotation.
    In the @JsonTypeInfo annotation the three properties use, include and property are used. The use property is configured as to use a minimal class name, for instance Circle or Rectangle, as a subclass discriminator. It does expose some properties (i.e. class names) in generated JSON representation and thus may not be optimal as far as security is concerned.
    The include property is configured to add a property to the JSON representation which name (shapeType) is specified by the property property.

The JSON representation of a circle entity, that is a subclass of Shape, may look like this:

Circle Class

The first of the concrete shapes is the circle, which adds a radius property.

While I would have wished that I could omit the default constructor in order to prevent creating anything but immutable instances, JPA needs it when instantiating entities.

Rectangle Class

The second, and last, concrete shape is the rectangle.

Drawing Class

In this very simplistic example, a drawing consists of an arbitrary number of shapes. In addition it has a name and a date on which it was created:

Note that:

  • The shapes of a drawing are stored in the shapes set.
    A drawing may contain many shapes and the shapes are owned by the drawing, meaning that they will be deleted if the drawing is deleted.
    A join-table is used to form associations between drawings and the shapes of drawings.

Spring Data JPA Repositories and Customization

The Spring Data JPA repositories would have been trivial if it weren’t for the fact that I want to merge entities with an id into the JPA context if they have been persisted earlier in a way not supported out of the box by Spring Data JPA.
One way of accomplishing this is, as in this example, implementing a custom method to be added to all Spring Data JPA repositories.

Adding a Custom Method to Spring Data JPA Repositories

Adding a custom method to the Spring Data JPA repositories of an application involves the following steps:

  • Create an interface that extends, for instance, JpaRepository and add the custom method to the interface.
  • Create an implementation class that extends SimpleJpaRepository and that implements the interface created in the previous step.
  • In the @EnableJpaRepositories annotation use the repositoryBaseClass element to specify the custom implementation class from the previous step.

Create the Custom Repository Interface

The custom repository interface contains but one single method, which I have named persist.

Note that:

  • The interface is annotated with the @NoRepositoryBean annotation.
    This was done to prevent Spring Data JPA from believing this interface is a repository interface.
  • The interface extends JpaRepository.
    There are other interfaces in Spring Data JPA that could be used as parent for this interface but I chose JpaRepository since it is the one with most features and the example program is indeed using JPA.
  • The database lock mode on the persist method is pessimistic write.
    The database lock mode should be chosen according to the needs of your application. I recommend having a look at the JavaDoc in the javax.persistence.LockModeType enumeration for more information.

Create the Custom Repository Implementation

The implementation of the custom repository base consists of two constructors and an implementation of the persist method.

Note that:

  • The class extends the SimpleJpaRepository class.
    This is the default implementation of a JPA repository provided by Spring Data JPA.
  • The class implements the JpaRepositoryCustomisations interface.
    This is the interface we created in earlier that defines the additions to Spring Data JPA repositories we want to make.
  • There is an instance variable of the type EntityManager.
    The custom repository method need to use the entity manager, so it will be saved in this instance variable when an instance of a repository is created.
    The superclass does contain an instance variable of the same type, but it is private and thus not accessible by child classes.
  • There are two constructors.
    Both constructors are from the superclass. In both constructors the entity manager is saved, for the reason described above.
  • The persist method is annotated with the @Transactional annotation.
    This was done to set any transaction that is created when invoking this method to not be read-only, which is the default set in the superclass SimpleJpaRepository.
  • There is an implementation of the persist method.
    Finally, there is an implementation of our custom repository method.

Configure the Repository Base Class

In order for the custom Spring Data JPA repository implementation to be used, we have to add the @EnableJpaRepositories annotation with the repositoryBaseClass element to the test classes and application class like in the examples below.

Unit-test class with the @EnableJpaRepositories annotation added:

Spring Boot main application class with the @EnableJpaRepositories annotation added:

Repositories

There are three repository interfaces in the example application, all of which are trivial. Below is the circle repository interface shown. Please refer to the repositories package in the GitHub repository for the other interfaces.

All three repository interfaces extend the custom repository interface we created earlier.

Services

Entities and repositories will be implemented the same way regardless of whether we use asynchronous Jersey and/or RXJava. The next step is the service layer, in which we later will see differences when RxJava is introduced.

Synchronous Service Base Class

All the services in the service layer of the example application have one common super-class, which implements basic functionality of the services.

Note that:

  • Java generics are used to determine the type of entity the service is to operate on.
    The entity type E must be a subtype of the entity base class LongIdEntity created earlier.
  • The class is annotated with the @Transactional annotation.
    All methods in service classes that inherit from this class will be executed in a transaction. The transaction boundary has been located in the service classes which may be used by different adapters of the application.
  • There is an instance variable of the type JpaRepositoryCustomisations.
    Using this type is how the customised Spring Data JPA repositories of the example application can commonly be referred to.
  • The class contains methods to support the common CRUD operations.
  • The find and findAll methods are annotated with the @Transactional(readOnly = true) annotation.
    This is a hint to the transaction system that no write or update operations will occur when these methods are invoked.

Concrete Service Classes

With the service base class in place, implementing a basic service becomes trivial, like in the example here showing the circle service:

The rectangle and drawing services are equally simple, so I have omitted them. Please refer to the services package in the GitHub repository for implementation details.

REST Resources

Let’s step up another layer. The REST resources exposes the services in a RESTful way over HTTP. As before, the HATEOAS part has been deliberately left out.

Jersey Configuration Class

Before the resource classes are implemented, a little Jersey configuration is necessary.

The above configuration class inherits from the Jersey ResourceConfig class, which represents a configurable JAX-RS context. Resource classes are not registered individually, instead we tell Jersey in which package to look for resource classes. The package is the same package as in which the Jersey configuration class is located, so if the resource classes are moved to another package, the Jersey configuration will have to follow or be modified.

REST Resources Base Class

As with the services, there is a common base-class for the REST resources which implement basic CRUD operations for an entity:

Note that:

  • The class is annotated with the @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) annotation.
    That a REST resource produces JSON is quite natural. The reason for also producing plain text is that in the case of errors, error messages will be returned in plain text.
  • There is no @Transactional annotation on the class.
    As you can recall from the comments on the service base class, the transaction boundary of the REST service is to be located in the service layer.
  • Similar to the service base class, Java generics are used to determine the type of entity the REST resources is to expose operations on.
    The entity type E must be a subtype of the entity base class LongIdEntity created earlier.
  • There is an instance variable named mService of the type AbstractServiceBasePlain<E>.
    This instance variable will hold the reference to the service used by the resource.
  • There is a method named performServiceOperation.
    This method takes three parameters; a lambda expression (of the type Supplier<Response>), an integer and a string. The lambda expression is evaluated. If no exception is thrown, the result is the Response object returned by the lambda expression, otherwise a new Response object is created in which the HTTP status code is set to the integer parameter and the payload is set to the string with the message from the exception appended.
    The purpose of this method is to perform operations in the REST resource classes of the application in a uniform manner and also to make the code cleaner..
  • In the performServiceOperation method, the type of the response payload created when exceptions occur is plain text.
  • There is an abstract method named entityListToArray.
    This method is supposed to take a list of entities and return an array of entities.
    First of all, this method is to be used when returning multiple entities, since I have encountered some problems when creating JSON representation from a list. The second reason for this method is that I haven’t found a way to create an array of entities from a list of entities when using generics. Thus it will be each subclass’ responsibility to implement this method.

Concrete Resource Classes

With the above abstract resource base class in place, the concrete resource classes are simple to implement. The example below show the circle resource class. Please refer to the restadapter package in the GitHub repository for the resource classes not shown here.

Note that:

  • The concrete resource class is annotated with @Component.
    This is in order for Jersey to be able to recognize the resource class when scanning the package we specified earlier in the Jersey configuration class.
  • A constant have been used as the parameter to the @Path annotation.
    This enables me to use the same constant in tests and thus have a “single source to the truth” as far as the resource path is concerned.
  • The constructor takes an instance of the circle service as a parameter.
    Spring will automatically discover the parameter when instantiating the resource class and inject the proper dependency. The reference to the service will be store in the superclass instance variable seen earlier.
    An alternative to constructor injection would have been to introduce an instance variable of the type CircleService in the concrete resource class and then call the setter in the superclass. However, I feel that having two instance variables that in effect refer to the same thing increases the risk for bugs.
  • There is an implementation of the abstract method entityListToArray from the super-class.
    Simple to do once the concrete types are available.

Tests

To paraphrase the lyrics from a song: A man ain’t no man if he ain’t got no tests.
The example program will have tests but before the actual tests are implemented, a few helpers are needed.

JSON Converter

This class is an old friend of mine – I use it over and over when I have to marshal and unmarshal JSON data. It uses the Jackson library.

Note that:

  • In the method createAndConfigureJsonObjectMapper an object mapper is created and configured which will not include representation for properties that are null when creating a JSON representation.
    While not strictly necessary to omit properties with null values, I have chosen to do so.

Entity Factories

Many are the times when I have thought about the mess that I myself have caused in my test classes. One significant source for this mess have often been code that creates objects or hierarchies of objects to be used in the tests. My latest attempt in this area is to create a factory class in the test code for each type of object that I want to create during tests.

All the entity factories implement one and the same interface:

In this example program, I have implemented three entity factories:

  • A circle entity factory.
  • A rectangle entity factory.
  • A drawing entity factory.

The drawing entity factory uses the circle and the rectangle entity factories to create shapes.

I will not show the implementation of these entity factories here. Please refer to the GitHub repository for details.

Repository Customisations Test

Since there are Spring Data JPA customisations, as described earlier, I feel it is natural to test these customisations:

Note that:

  • The class is annotated with the @SpringBootTest annotation.
    This annotation is used on tests, both JUnit and TestNG, in Spring Boot applications.
  • The class is annotated with the @EnableJpaRepositories annotation.
    As in the section on Spring Data JPA repository customisations earlier, this annotation is required to actually use the custom repository implementation.
  • The test class extends the class AbstractTestNGSpringContextTests.
    Since this test is intended to be a TestNG unit-test, the test class must extend this base-class when developing a Spring-based application.
  • Testing is performed on the circle repository.
    The Spring Data JPA customisations in this example are applied to all the repositories, so I just chose one repository at random to test on.

REST Resources Tests

When testing REST resource classes, I have used a strategy similar to what was seen with the service classes; an abstract base-class that uses Java generics that is later subclassed for each REST resource class to test. This base-class can be extended for a specific resource type and will then provide a basic set of tests for the resource type in question. Tests that are specific to a certain resource type may be added to the subclass as desired.

REST Resources Test Base Class

The abstract REST resource test base class looks like this:

Note that:

  • The class is annotated with the @SpringBootTest annotation.
    As before, this annotation is used on tests, both JUnit and TestNG, in Spring Boot applications. In addition there is the webEnvironment element with the value SpringBootTest.WebEnvironment.DEFINED_PORT. This will cause tests inheriting from this class to run in a real, embedded, web container (as opposed to a mock servlet environment) using the defined port (as opposed to a random port).
  • The class is annotated with the @EnableJpaRepositories annotation.
    As in the section on Spring Data JPA repository customisations earlier, this annotation is required to use the custom repository implementation.
  • The test class extends the class AbstractTestNGSpringContextTests.
    As before, this is required with TestNG-based test classes.
  • Java generics are used to determine the type of entity the resource exposes operations on.
    The entity type E must be a subtype of the entity base class LongIdEntity created earlier.
  • There is a constant, ENDPOINT_PORT, that determines to which port resource requests over HTTP will be sent to.
  • There is a constant, TEST_TIMEOUT, which determine the time in milliseconds within which a test must complete, or else it will fail due to timeout.
  • The instance variable mEntityFactory is to hold a reference to an instance of one of the entity factories we developed earlier.
    The entity factory will be used to create instances of entities in the tests.
  • The instance variable mEntityRepository holds a reference to a repository for the entity type related to the tested REST resource.
    The repository is used in the tests to verify that the requests to the REST resource gives the desired result.
  • The instance variable mResourceUrlPath is to contain the path for the REST resource that is to be tested.
    For example, in the case of the REST resource operating on rectangles, this will be “/rectangles”, which is the value of the constant RectangleResource.PATH seen earlier.
  • The instance variable mExpectedEntity will contain a reference to an entity which has already been persisted.
    The tests will try to retrieve, delete and update this entity using requests to the REST resource.
  • The instance variable mCreateEntityIndex will contain the seed value used when creating the expected entity mentioned above.
    It is saved in order for tests to be able to create an entity using a seed value that has not been used.
  • There is a method setUpRestAssured annotated with the @BeforeTest annotation.
    This method will be executed once before the tests in a concrete test class are run. It prepares the RestAssured test framework.
  • There is a method prepareBeforeTest which is annotated with the @BeforeMethod annotation.
    This method will be invoked once before each test method is executed. In this base-class, this method creates and persists an entity. This method will be overridden by subclasses, as we soon will see, in order to perform subclass-specific initialization.
  • In the testGetEntity, testCreateEntity and testUpdateEntity test methods, an assertion named assertLenientEquals is used.
    This an Unitils assertion which, using Java reflection, compares the values of each field in the two objects. Lenient assertion means that the order of items in a collection or array is not significant and that Java default values for fields, such as null, zero or false, will be ignored when comparing two objects.

Concrete Resource Tests

As an example of a concrete REST resource test-class, we will have a look at the circle resource test.

We can see that:

  • A reference to the circle repository is to be autowired into the instance variable mCircleRepository.
    The reference in this instance variable is later copied to the parent-class’ instance variable mEntityRepository seen earlier.
  • The instance variables mEntityFactory and mResourceUrlPath are set up as appropriate for the circle entity type.
  • The superclass’ method prepareBeforeTest is invoked.
    It is important to invoke this method and to invoke it only after all the instance variables of the parent-class have been set up properly.

The rectangle and drawing resource tests are very similar, so I will not show them here. They are available in the example program repository.

Final Words Part One

You should be able to run all the tests in the example program without any failures.
In the next article in this series we will look at how to load-test the example REST service using Gatling.

Happy coding!

One thought on “REST with Asynchronous Jersey and RXJava – Part 1

  1. Oleh

    Thank you, Ivan. I really enjoyed these series about the performance testing. Really cool blog! Keep rocking’ mate

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter Captcha Here : *

Reload Image