Using IndexedDB on Web Browser with Well Known Design Patterns — Only with Java by Mrs. Gwitany and Dr. Jackl

Dr. Lofi Dewanto
Oct 28, 2020 · 8 min read

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

The structure of the Maven project indexeddb-elemental2-dagger2-example

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:

GWT Boot — pom.xml

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:

GWT Boot — pom.xml Maven plugin

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

Entry Point — Main Method

Which Entry Point should be called, has to be defined in the GWT Module Definition file: module.gwt.xml.

DI: Dagger2

Annotation Comparison Spring Framework / Boot vs. Dagger2

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.

After running mvn compile Dagger2 will generate some Java files to manage the dependency injection for you. Dagger2 uses code generator to create the factories and this is also the big difference with Spring Boot which mostly uses dynamic proxies and reflections. In the world of JavaScript we don’t have Reflection APIs, therefore code generator is here the solution.

Generated Files from Dagger2 in target/generated-sources

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.

Using Dagger2 to Inject Dependencies for ProductService

Service and Repository Pattern

Repository.java — General Interface for 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.

Product Service, Repository, RandomCreator and Product Entity
  • 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

Product product = new Product.Builder(key, 
"Lofi " + key).setType(type).setAmount(10)
.setPrice(price)
.build();

Following is the code of the Product entity in which the Builder pattern is also implemented.

Product Entity as Rich Domain Model

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

ProductComposite as a Simple UI

Mrs. Gwitany and Dr. Jackl will handle the UI development in detail later in another article, because GWT / J2CL offers a lot of UI frameworks, in amount almost comparable with the JavaScript and old Java world.

Mock Test

ProductCompositeTest — Unit Test for ProductComposite View / UI

The Result

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.

GWT Development Mode with Jetty Web Server

Following Web app can be tested afterwards. You can also take a look at the IndexDB viewer on the Application tab of Google Chrome.

IndexedDB Example — Logging
IndexedDB Example — IndexedDB Content

Note 1: the Web browser app tested only with Chrome and Firefox. In Firefox you could not use private mode to run IndexedDB.
Note 2: the app works with Java 8 or Java 11 since GWT 2.9 supports Java 11 but don’t forget that the result of your app is always a JavaScript app.

Epilog

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!

Star Gazers

“If you want to master something, teach it.”

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store