JsonDB: a Opensource, Java-based, Database

stores its data as .json files

Small memory footprint, runs embedded within your Java program,

Provides APIs that are very similar in names and semantics to those of Spring Data for MongoDB,

Supports encryption of data, XPath based search/find queries.

Checkout on GitHub

Why

Why Jsondb

You have a Java based program (or even Android App) and you:

  • Need a light weight database of some kind to store a small amount (a few 1000 rows) of data,
  • Need a pure java, easy to use, thread safe database,
  • Need some ORM support,
  • Need a good query interface,
  • Okay with Mongodb like per API level atomicity (okay with eventualy data consistency),
  • Want to be able to easily add, edit, update, delete the db data files, even when Jsondb is running,
  • Want to be able to move the db files seamlessly, download updated files over network while db is running,
  • Want to be able to safegaurd sensitive data (passwords etc) in the db data files, with some high strength encryption,

Why NOT Jsondb

  • Jsondb loads the db data files into memory, all API’s return deeply cloned objects so you will need minimum as much memory as the size of data files and some more,
  • Jsondb does not have full transaction support (does support Mongodb like atomic API’s)
download

Getting Jsondb

Stable Jsondb builds are uploaded to Maven Central

  • You can download the jar, source-jar or javadoc-jar from Maven Central and use it in the traditional way by adding it into your classpath. Jsondb uses quite a few of other opensource java libraries so doing it this way will involve getting all those libraries and adding to your classpath.
  • Optionally (Recommended) if you use Maven, Gradle or any such build system you can get it as a dependency using the appropriate dependency code.
  • Since March 2019 two different builds are released, Each version is suffixed with -j8 or -j11. First one is built using Jdk version 1.8(LTS) and second one is built using Jdk version 11(LTS). This is to facilitate users who are still on Java 8.

Example:

<!-- https://mvnrepository.com/artifact/io.jsondb/jsondb-core -->
<dependency>
  <groupId>io.jsondb</groupId>
  <artifactId>jsondb-core</artifactId>
  <version>1.0.106</version>
</dependency>
usage

Using Jsondb

The best way to understand usage of JsonDB is to look at code of the many Junit tests in its source code. Every possible scenario is covered in these junit test classes.

For those of you who need a quick intro: The main class to use in Jsondb is: io.jsondb.JsonDBTemplate JsonDBTemplate can be used in a very similar way as Spring Data MongoTemplate class.

Instantiating JsonDBTemplate

//Actual location on disk for database files, process should have read-write permissions to this folder
String dbFilesLocation = "<path on disk to save or read .json files from>";

//Java package name where POJO's are present
String baseScanPackage = "com.mypackage.model";

//Optionally a Cipher object if you need Encryption
ICipher cipher = new Default1Cipher("1r8+24pibarAWgS85/Heeg==");

JsonDBTemplate jsonDBTemplate = new JsonDBTemplate(dbFilesLocation, baseScanPackage, cipher);

Defining a POJO

Every object that you wish to save in JsonDB must be a POJO (Plain Old Java Object) that satisfies the JavaBean programming conventions. Each object must implement either Serializable or Externalizable, must have a no-arg(default) constructor, and each of its properties(attributes) must have public setter and getter methods. The names of these methods must be as per the JavaBean naming conventions.

Note the package in the POJO its the same as the 2nd argument we passed while instantiating the JsonDBTemplate object. Also note the 3 annotations in the POJO:

  • @Document : this annotation signifies that this POJO is a Jsondb Collection, the attribute collection specifies the name of the .json file on disk, the attribute schemaVersion specifies schema version this support is not yet completed.
  • @Id : this annotation signifies that this field is the primary key in the collection. Jsondb supports only one Id field per collection.
  • @Secret : this annotation signifies that the value of this field should be encrypted before writing to disk.
package com.mypackage.model;

import io.jsondb.annotation.Document;
import io.jsondb.annotation.Id;
import io.jsondb.annotation.Secret;

/**
 * A test Pojo representing a imaginary class Instance.
 * @version 1.0 28-Sep-2016
 */
@Document(collection = "instances", schemaVersion= "1.0")
public class Instance {
  //This field will be used as a primary key, every POJO should have one
  @Id
  private String id;
  private String hostname;
  // This field will be encrypted using the provided cipher
  @Secret
  private String privateKey;

  public String getId() { return id; }
  public void setId(String id) { this.id = id; }
  public String getHostname() { return hostname; }
  public void setHostname(String hostname) { this.hostname = hostname; }
  public String getPrivateKey() { return privateKey; }
  public void setPrivateKey(String privateKey) { this.privateKey = privateKey; }
}

Creating a collection if it does not exist

jsonDBTemplate.createCollection(Instance.class);

Inserting a document into a collection

Instance instance = new Instance();
instance.setId("11");
instance.setHostname("ec2-54-191-11");
instance.setPrivateKey("b87eb02f5dd7e5232d7b0fc30a5015e4");
jsonDBTemplate.insert(instance);

Removing a document from a collection

Instance instance = new Instance();
instance.setId("000012");
jsonDBTemplate.remove(instance, Instance.class);

Save a document into a collection

Instance instance = new Instance();
instance.setId("000015");
jsonDBTemplate.save(instance, Instance.class);

Upsert a document into a collection

Instance instance = new Instance();
instance.setId("07");
instance.setHostname("ec2-54-191-07");
instance.setPrivateKey("PrivateRyanSaved");
instance.setPublicKey("TomHanks");
jsonDBTemplate.upsert(instance);

Find a document when you know the Id

jsonDBTemplate.findById("000000", Instance.class);

XPath based Queries in Jsondb

XPATH syntax allows for numerous ways to query and locate document(s) of interest. Below are few examples:

Find a document(s) with equals criteria

String jxQuery = String.format("/.[id='%s']", "01");
List<Instance> instances = jsonDBTemplate.find(jxQuery, Instance.class);

Find a document(s) with NOT equals criteria

String jxQuery = "/.[not(privateKey='')]";
List<Instance> instances = jsonDBTemplate.find(jxQuery, Instance.class);

Find a document(s) with greater than criteria

String jxQuery = String.format("/.[id>'%s']", "01");
List<Instance> instances = jsonDBTemplate.find(jxQuery, Instance.class);

Find and Remove first document based on query as Atomic operation

String jxQuery = String.format("/.[id>'%s']", "04");
Instance removedObjects = jsonDBTemplate.findAndRemove(jxQuery, Instance.class);

Find and Remove all documents based on query as Atomic operation

String jxQuery = String.format("/.[id>'%s']", "04");
IList<Instance> removedObjects = jsonDBTemplate.findAllAndRemove(jxQuery, Instance.class);

Find and Modify first document based on query as Atomic operation

Update update = Update.update("privateKey", "SavingPrivateRyan");
update.set("publicKey", "SavedByPublic");

String jxQuery = String.format("/.[id='%s']", "03");
Instance retInstance = jsonDBTemplate.findAndModify(jxQuery, update, "instances");

Find and Remove all documents based on query as Atomic operation

Update update = Update.update("privateKey", "SavingPrivateRyan");
update.set("publicKey", "SavedByPublic");

String jxQuery = String.format("/.[id>'%s']", "03");
List<Instance> retInstances = jsonDBTemplate.findAllAndModify(jxQuery, update, "instances");

Sorting and Slicing in Jsondb

Sorting Jsondb allows you to obtain a sorted result with the find() and findAll() methods.

Comparator<Instance> comparator = new Comparator<Instance>() {
  @Override
  public int compare(Instance o1, Instance o2) {
    return (o1.getSomeAttribute().compareTo(o2.getSomeAttribute()));
  }
};
List<Instance> instances = jsonDBTemplate.findAll(Instance.class, comparator);

Slicing Jsondb slicing feature is similar to the python/numpy slicing feature. Slice string parameter is expected in format i:j:k and should following all the rules similar to the slicing feature in python/numpy. Slicing can be used in combination with sorting or without sorting

List<Instance> instances = jsonDBTemplate.findAll(Instance.class, null, "0:7:2");

Encryption support in Jsondb

  • If you do not need encryption support simply use a JsonDBTemplate constructor that does not require a cipher argument or pass null. Make sure you are not using the @Secret annotation in any of your POJO’s.

  • However If you do need encryption support then as in the examples above instantiate a instance of io.jsondb.crypto.Default1Cipher class and pass that when instantiating JsonDBTemplate.

  • If you need help creating a secure Symmetric Key for the above default cipher use the following standalone.

String base64EncodedKey = CryptoUtil.generate128BitKey("SomeSecretPassword", "SomeUniqueSecreteSalt");
  • If you need a 192bit or 256bit secure Symmetric Key ensure that you have the Unlimited Strength JCE Policy jars in your JRE\lib\security folder and then write a modifed method similar the the CryptoUtil.generate128BitKey(). Compile and Execute it and use the key when instantiating JsonDBTemplate.

  • If you need a custom encryption support say DES Encryption you can implement the interface io.jsondb.crypto.ICipher and then use that when instantiating JsonDBTemplate.

  • At some later time if you need to change the cipher and/or the key used then use the below api. Make sure you back up the database files in case something goes wrong.

ICipher newCipher = new Default1Cipher("SomeNewKey");
jsonDBTemplate.changeEncryption(newCipher);