Kefei

💙 Kefei 💙

Persistent Variables in Kotlin

Ive always thought databases were a total pain to setup and as a developer I found it genuinely suprising why there werent more technologies that focused on easily integrating databases into your application without so much setup and configuration. Pretty much every server/api/application I have ever worked on that had a genuine use case needed to persist data of some sort and had a database integration, although in many of these cases, the data being persisted could of easily been stored in a local data structure.

That is in brief my reason for creating Kefei, which is essentially an alternative to remote databases and one of its goals is to be simple and easy to setup and configure. Kefei automatically persists and loads your local application data structures. It can support multiple different adaptors but out of the box it persists data structures by writing them to the local file system.

Kefei is written in Kotlin, so to use Kefei, youll have to be using Kotlin as well. However, getting started is pretty simple.


class MyClass: Persistable() {

    @Persist
    lateinit var myImportantList: MutableList<String> /* The value of this field is persisted */

    lateinit var notImportantStr: String /* The value of this field is not persistedm its just a regular class property */

    @Persist
    lateinit var myImportantStr: String /* The value of this field is persisted */
    
    /* Whatever else you want... */
}

As you can see from the code snippet below, in order to start persisting your local variables, the class containing the field which you want to persist must extend from the abstract base class Persistable, and then the field itself must be marked with the annotation @Persist. Only if both these conditions are true, Kefei will - Register a JVM shutdown hook that serializes these field values and persists them,. * Serialization format and perisent storage medium can be configured - Automatically load these values from storage next time the same class in instantiated.

- The `save()` and `load()` functions can be called at any time, but automatically they are called when the JVM shuts down and then when the same class is next instantiated. 

You may be thinking at this point that this totally defeats the point of OOP if all objects instantiated from the same class have the same values in their properties. Well, I have two things to say to that:

  1. Although the save() and load() functions are called automatically by the kefei framework, there is an options file where this can be overidden, so that these functions would have to be called manually, but this gives you the option to call these functions on the object which you want to save and load values from, and pass in the path to where these values should be loaded from.

  2. When you instantiate a class that extends from the abstract base class Persistable, you can pass in a constructor paramater, such as an object identifier or UUID so that the path where the values for this object will be saved will derived from this value. For example, usually the path were object value will be saved is: ` ./${options.dir}/${class.name}/${field.class.name}/${field.name} ` but if you were to pass an object ideniifier as described above, the path would now become: ` ./${options.dir}/${class.name}/${object.identifier}/${field.class.name}/${field.name} `

Ofcourse, youll have to remember this object identifier for when you next want to load these values.

I will admit this is a long way from a perfect solution, but I do believe it attempts to solve a genuine problem, and I will develop it further when I get the chance to use it in another project.

You can find the source on Github here …aaand in case you were wondering, Kefei is was my girlfriend, and this project is dedicated to her, I think she would appreciate it because she finds databases pretty annoying as well.