Using IndexedDB on Web Browser with Well Known Design Patterns — Only with Java by Mrs. Gwitany and Dr. Jackl
In the article “Using IndexedDB in Web Browser — All in Java” Mrs. Gwitany and Dr. Jackl told us how we could use Java with Elemental2 to build a simple prototype based on WebAPIs for IndexedDB. This time they’ll show us how to build the already shown code to be testable and maintainable with all the Design Patterns we already know from our server-side experiences with Java.
In the server-side Java world we use following patterns all the time, so we want to use them in the Web browser apps as well:
- Dependency Injection: we inject dependent object into a main object so that we could easily mock the injected object to be able to test the main object in a simple unit test. This is very useful especially if the dependent object uses e.g. database which can’t be booted very quickly.
- Service and Repository Pattern: we build services and those services access data repositories to be able to call the database operations.
- Rich Domain Model: we don’t want to build anemic domain model which contents only data, instead we also want to have some logics in it which is called rich domain model.
- Builder Pattern: we build our object step-by-step using correct sequence of actions to be able to manage the creation of that object.
- Mock Test: as mentioned before it is very important to be able to mock the behavior of dependent objects so that you don’t need to use real database for your unit test.
Lesson 1: to build maintainable and extensible Web browser app you need to use the known design patterns you already learned from the server-side Java.
To show how we could use the patterns Mrs. Gwitany has created a small example indexeddb-elemental2-dagger2-example based on IndexedDB which we have seen in the last article. Following libraries and frameworks are used in the example:
- Dependency Injection: Dagger2 is designed to be flexible and uses fully static, compile-time generator for Java, Kotlin and Android.
- Service and Repository Pattern: no special framework for Service and for Repository Pattern we use a generic Repository Pattern which is designed from this class: Repository.java
- Rich Domain Model: no special framework, we just have a calculated property getCalculatedPriceWithAmount on our Product.java class
- Builder Pattern: some possibilities are using Project Lombok, AutoValue and Immutables framework. This time we just build the Builder Pattern manually, but next time we would try to use Immutables for this pattern.
- Mock Test: for this purpose we use JUnit 5 and Mockito (see pom.xml)
So, let’s deep dive into the example project!
Maven Project Structure
Before we are looking into the project in detail let’s see the structure of the Maven project on Eclipse STS 4 below.
The project based on Maven and Mrs. Gwitany uses GWT Boot to simplify the pom.xml. GWT Boot Starter dependencies is basically a simple Starter dependencies collection for GWT just like Spring Boot Starter dependencies. The idea is taken from Spring Boot Starters. Here is the important part of the pom.xml which is based on GWT Boot Starter dependencies:
Mrs. Gwitany uses two Starter dependencies:
- gwt-boot-starter-dagger2: dependencies to Dagger2. All GWT dependencies are included as transitive dependencies.
- gwt-boot-starter-elemento-core: dependencies to Elemento. This library makes working with Elemental2 a lot more easier.
Other dependencies like elemental2-indexeddb can be added independently. Also don’t forget to add the needed modules to the GWT Module Definition: module.gwt.xml.
GWT Boot uses GWT Maven Plugin and it should be configured like below:
With this pom.xml you are ready to go. More information how to setup a Maven project with GWT Boot please see GWT Boot Samples.
Lesson 2: use GWT Boot Starter modules to make your pom.xml easier to manage. No need to copy&paste the dependencies with the matching versions.
Main Method == Entry Point
In GWT your app starts with the loading the code in Entry Point. So this is comparable with the Java Main Method. In this Entry Point we just simply initialize the Dagger2 framework with the root view / UI component ProductComposite.
Which Entry Point should be called, has to be defined in the GWT Module Definition file: module.gwt.xml.
If you know Spring Boot with its Dependency Injection (DI) annotations then it is easy to use Dagger2. This table below shows the similarity between Spring Boot and Dagger2 DI annotations.
Following Modules and Components should be implemented by the user of Dagger2:
- AppModule: in this module we don’t define any object creations because we use @Singleton on each class to be managed by Dagger2.
- AppComponent: in this component we define the entry point for the class ProductComposite. The class ProductComposite is the root component view / UI of the Product domain.
How could we use the DI framework afterwards? Just as simple as this example below. The class ProductService uses constructor injection to inject two other classes ProductIdbRepository and ProductRandomCreator which can be used later in the method createProduct.
Service and Repository Pattern
For the Repository Pattern we could define a general interface like Repository.
ProductIdbRepository implements the interface for the IndexedDB operations which consists the Product entity. The implementation of IndexedDB is quite straight forward. In the example Mrs. Gwitany only implemented the persist method. The rest is open for you to implement. ProductRandomCreator is the class where we create some products since we don’t have any possibility to create products from the user interface.
Both classes will be injected into ProductService in its constructor like we have seen above.
Following class diagram shows us the structure of the Product domain model.
- ProductService <<Service>>: serves to create products and will be used directly from the user interface ProductComposite.
- ProductRandomCreator <<Service>>: creates some products randomly.
- ProductIdbRepository <<Repository>>: offers CRUD (Create Read Update Delete) operations for IndexedDB Web browser database.
- Product <<Entity>>: is the entity which should be created and managed by the repository.
Entity: Rich vs. Anemic Domain Model and Builder Pattern
As we have seen above the Product is the entity in the domain model. Mrs. Gwitany made the the Product entity a rich one since it also calculates the price with the given amount in the method called getCalculatedPriceWithAmount. She also creates a Builder Pattern to be able to instantiate the product nicely. So here is how we could create the Product entity with the Builder Pattern:
Product product = new Product.Builder(key,
"Lofi " + key).setType(type).setAmount(10)
Following is the code of the Product entity in which the Builder pattern is also implemented.
Lesson 3: Dependency Injection, Service, Repository, Entity and Builder can be used also on Web browser with Java and GWT / J2CL. Please remember, we have Design Patterns because we’ve learned that they help us to structure our app so that it will be better maintainable and extensible.
User Interface Composite
After we have the domain model we just need the view / UI. For this purpose Mrs. Gwitany created the class ProductComposite. It needs the the ProductService, so it is injected into the ProductComposite. The renderView method build the HTML DOM tree with the help of Elemento library. The UI is very simple so that we can concentrate on the basics. The event handler onProductCreated will be call every time when the user clicks the button. It has some “presentation logic” which controls the creation of input field or just a simple logging on console.
Last but not least, actually this a very important part which Mrs. Gwitany and Dr. Jackl told me, within Java you can use your well known test frameworks like JUnit and Mockito. In these two unit test classes you can find some interesting tests:
- ProductCompositeTest: this class tests the ProductComposite UI class. It uses Mockito and tests the behavior of the event handler onProductCreated, which is shown below. To be able to test the “presentation logic” you need to separate the rendering method from the logic, so that you can partial mock the class with spy.
- ProductServiceTest: this class tests the service class business logic.
How does the Web app look like? Just go to the directory of the Maven project indexeddb-elemental2-dagger2-example and run following command:
mvn gwt:generate-module gwt:devmode
You’ll see following Swing app and you can copy&paste the Web browser address or just push the button to launch the default browser on your system.
Following Web app can be tested afterwards. You can also take a look at the IndexDB viewer on the Application tab of Google Chrome.
Note 1: the Web browser app tested only with Chrome and Firefox. In Firefox you could not use private mode to run IndexedDB.
In the next article Mrs. Gwitany and Dr. Jackl will show us how to use some pretty UI frameworks with all those fancy design like Material Design and Bootstrap. Also how to access the server-side Spring Boot REST APIs to be able to show how to reuse codes for client and server. Until then enjoy reading and don’t forget to play with GWT and J2CL!
All examples can be found at:
Padlet for GWT / J2CL modern programming: