Using IndexedDB in Web Browser — All in Java with Mrs. Gwitany and Dr. Jackl

Dr. Lofi Dewanto
Sep 15 · 7 min read

This story isn’t about Java Applet or Java WebStart, this story is a pure JavaScript story presented by Mrs. Gwitany and Dr. Jackl, generally known as GWT and J2CL.


In the world of web browser JavaScript is the king, so all the Web APIs are based on JavaScript. The Mozilla Developer Network (MDN) is the source of truth for the Web APIs. It looks awesome and it explains everything with examples very nicely. So if you want to build web apps you surely need the MDN documentation.

Image for post
Image for post
MDN is Your Best Friend for Web APIs

Lesson 1: consider Mozilla Developer Network (MDN) and Web APIs as your best friend.

In this story I will show you how we can use Web APIs from GWT / J2CL transpiler. For this purpose I chose IndexedDB API. From the documentation on MDN here is the definition of IndexedDB API:

IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. This API uses indexes to enable high-performance searches of this data. While Web Storage is useful for storing smaller amounts of data, it is less useful for storing larger amounts of structured data. IndexedDB provides a solution.


Following simple logic should be implemented with IndexedDB:

  1. The web app will create an IndexedDB database when a user open the web app for the first time. If there is no database / datastore available it will create a new database and insert some values.
  2. If we open the web app for the next time and the database is already there, the web app will just insert some values. That’s all.

As we have learned from the article “Learn Once Use Everywhere: Using JavaScript APIs in Java for Web Browser” we need JsInterop classes which bridge the access from Java to the IndexedDB API (use case 2). Surely we can build the JsInterop classes manually by ourself but we don’t have to. Elemental2 library from Google is here to help. Elemental2 library is a thin bridge and it contains a collection of JsInterop classes to access available Web APIs. We can use these classes directly in our Java web app. So what are the steps to use Elemental2 library? Here you are…

First Step: you need to add the needed Maven dependencies, in this case the IndexedDB Elemental2 library, to your pom.xml.

<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-indexeddb</artifactId
<version>1.1.0</version>
</dependency>

Lesson 2: before you create JsInterop classes manually take a look at Elemental2 library, for most Web APIs there are already the JsInterop classes created for you.

Second Step: The documentation of Elemental2 library for IndexedDB is very rare, so you need to use the MDN documentation for IndexedDB. The documentation is great and comes with some examples. For the IndexDB topic there are also some good documentations and articles:

With above docs and articles you are ready to implement IndexedDB functions with Elemental2.

Lesson 3: search for articles and documentations about the topic first. Most of the articles are for JavaScript but don’t panic, you will understand what you have to do in Java since it is very similar. Remember: the programming model in JavaScript is mostly based on events, promises, asynchronous programming model. The Elemental2 APIs will look very similar to the JavaScript APIs.

Third Step: The first problem I encounter was to check, whether IndexedDB is available on the web browser with following JavaScript code:

if ('indexedDB' in window) {
console.log('This browser doesn\'t support IndexedDB');
return;
}

After asking to the GWT Gitter Chat (this is definitely the place to ask for GWT / J2CL / Elemental2 topics) I got following solutions in Java:

// General solution with JsInterop
Window window = DomGlobal.window;
if (Js.asPropertyMap(window).has("indexedDB") {
logger.info("IndexedDB found");
}
... or ...// Use Elemental2 specific global variable
IDBFactory indexedDB = IndexedDbGlobal.indexedDB;
if (indexedDB != null) {
logger.info("IndexedDB found");
}

After getting the solution for the first obstacle, the rest is easy as things are working just the same as in the JavaScript solution. Very interesting is the asynchronous programming model in JavaScript which is not usual for Java developers. Here is the code for checking the database / datastore when it is not there yet, so you need to create it first.

JavaScript:

openDBRequest.onupgradeneeded = function(event) {
// Create object store from db or event.target.result
};

Java with Lambda:

openDBRequest.onupgradeneeded = event -> {
// Create object store from db or event.target.result
return null;
};

As you can see the code is quite similar. The return “null” in Java is not nice but it is needed because the Elemental2 libraries are generated from Closure libraries (more on the generation topic later).


With these three steps you would be able to finish the implementation of the simple logic for IndexedDB above. The complete Java class is implemented in the file IndexedDbElemental2.java. Now we can run the web app. Just go to the directory of the Maven project indexeddb-elemental2-example and run following command:

mvn gwt:generate-module gwt:devmode

We can debug the Java code, change it and reload it. Everything will be automatically transpiled and hot reloaded. Debugging works very well by adding a breakpoint on the sourcemaps in Google Chrome.

Image for post
Image for post
Debugging in Google Chrome — IndexedDbElemental2 Java class

To see the result you just need to go to the “Application” bar on the Chrome and look for the “Storage” area on the left. At the menu IndexedDB you will find our generated database and datastore. By clicking the “refresh” button to the table you can see the content of the datastore. In this example we save the Product object on each reload of the index.html. On each reload we create the IndexedDbElemental2 object and open the database. Here is the EntryPoint class AppEntryPoint:

package com.github.lofi.client; 
...
public class AppEntryPoint implements EntryPoint {
@Override
public void onModuleLoad() {
new IndexedDbElemental2().openDb();
}
}
Image for post
Image for post
Checking the result in the IndexedDB storage on Google Chrome

That’s it! You can check the whole file IndexedDbElemental2 and you’ll see that the shape is quite similar to the JavaScript example, which makes for us very easy to implement as long as we can find some good JavaScript articles or examples for the topic.


To conclude this story I want to show you the background how Elemental2 libraries are built. The Elemental2 libraries are mostly generated with the help of JsInterop Generator. Here is the description of JsInterop Generator project:

The jsinterop generator is a Java program that takes closure extern files as input and generates Java classes annotated with JsInterop annotations. This project is used for building Elemental2 [library]. Any other uses are experimental. You can use it to generate Java APIs for other JavaScript libraries but we don’t provide any official support. Feel free to open issues on the GitHub issue tracker, though.

It is important to know that we actually can get the JsInterop files through automated generation since they are only contracts between Java and JavaScript world.

In the mean time there is also another generator Webtack Generator which generates the JsInterop files with more Java orientation and nicer Javadocs. Do you remember the “return null” above? Here on this page you can see the differences of generated file by JsInterop Generator (Elemental2) and Webtack Generator (aka. Elemental3). For a comparison I created the same project but using Webtack JsInterop for IndexedDB: indexeddb-elemental3-example. Check it out and take a look the IndexedDB API (IndexedDbElemental3), it looks cleaner and more Java oriented.

Lesson 4: try to generate the JsInterop files you need, check whether someone works for Mrs. Gwitany and Dr. Jackl already did this or use JsInterop Generator / Webtack Generator to generate them automatically. Remember: JsInterop files are only the contract between Java and JavaScript world.


Mrs. Gwitany and Dr. Jackl are not alone with their transpiler tooling. TypeScript transpiler and Kotlin to JavaScript transpiler are quite similar. The main difference is if you use Spring Boot (Java) on the server side you have the same language, tooling and bullet proof mechanism also on the client side on the browser, so you can Learn Once Use Everywhere!

This diagram below shows the way to access the Web Browser APIs from Java.

Image for post
Image for post
Transpiling from Source Languages (Java, Kotlin and TypeScript) to JavaScript

Epilog: Many greets from Mrs. Gwitany and Dr. Jackl and I hope you also enjoy the four lessons mentioned in this story. Next time they’ll show us how to make this IndexedDB example more maintainable and testable by using Dependency Injection, Service / Repository pattern and Mock object — which are a bullet proof mechanism in developing Java apps for and from Java developers.


All examples can be found at:
https://github.com/lofidewanto/jsinterop-simple-jsframework-example

Padlet for GWT / J2CL modern programming:
https://bit.ly/GWTIntroPadlet

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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