ObjectBox – Embedded Database for Java Desktop Apps

ObjectBox does not only work with Android projects, but also for plain Java (JVM) desktop apps running on Windows, Linux, and macOS. Just like on Android, ObjectBox stands for a super simple API and high performance. It’s designed for objects and outperforms other database and ORM solutions. Because it is an embedded database, ObjectBox runs in your apps’ process and needs no maintenance. Read on to learn how to create a Java project using ObjectBox. We believe it’s fairly easy. Please let us know your thoughts on it.

Desktop Project Setup

Because ObjectBox comes with a Gradle plugin, you use Gradle as a build system. For this, in your project’s build.gradle file, you simply apply an annotation processor plugin (e.g. via gradle-apt-plugin) and the ObjectBox Gradle plugin. This must be done after applying the Java plugin.

This is how a Gradle build file using ObjectBox typically looks like:

buildscript {
ext.objectboxVersion = '2.2.0'
repositories {
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath "net.ltgt.gradle:gradle-apt-plugin:0.15"
classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
}
}
repositories {
jcenter()
}
apply plugin: 'java'
apply plugin: 'net.ltgt.apt-idea' // annotation processor plugin
apply plugin: 'io.objectbox'

This set up is the main difference between the Android and plain Java desktop setup. Other than this, ObjectBox works the same across platforms.

Native Libraries

Under the hood, ObjectBox is an object database running mostly in native code written in C/C++ for optimal performance (there’s no way to make this work as fast in plain Java). Thus, ObjectBox will load a native library: a “.dll” on Windows, a “.so” on Linux, and a “.dylib” on macOS. By default, the ObjectBox Gradle plugin adds a dependency to the native library matching your system. This means that your app is already set up to run on your system.

Note: on Windows you might have to install the Microsoft Visual C++ 2015 Redistributable (x64) packages to use the ObjectBox DLL.

Note that ObjectBox binaries are build for 64 bit systems for best performance. Talk to us if you require 32 bit support.

Add Libraries for distribution

While the default build configuration ensures that your app runs on your development system, you may want to support all major platforms (Windows, Linux, macOS) when you distribute your app. For this, just add all platform dependencies to your project’s build.gradle file like this:

dependencies {
// Optional: include all native libraries for distribution
implementation "io.objectbox:objectbox-linux:$objectboxVersion"
implementation "io.objectbox:objectbox-macos:$objectboxVersion"
implementation "io.objectbox:objectbox-windows:$objectboxVersion"
}

For reference, the following dependencies to the ObjectBox Java API and annotation processor are added by default by the ObjectBox Gradle plugin. Usually, there’s no need to set them up manually:

dependencies {
// Added automatically by the plugin - just for reference.
implementation "io.objectbox:objectbox-java:$objectboxVersion"
annotationProcessor "io.objectbox:objectbox-processor:$objectboxVersion"
}

Optional: Change the Model File Path

By default, the ObjectBox model file is stored in module-name/objectbox-models/default.json. You can change the file path and name by passing the objectbox.modelPath argument to the ObjectBox annotation processor.

In your project’s build.gradle file after the java plugin, add the necessary compiler argument:

class="lang:default decode:true">tasks.withType(JavaCompile) {
options.compilerArgs += [ "-Aobjectbox.modelPath=$projectDir/schemas/objectbox.json" ]
}

Optional: Change the MyObjectBox package

1.5 or newer

By default the MyObjectBox class is generated in the same or a parent package of your entity classes. You can define a specific package by passing the objectbox.myObjectBoxPackage argument to the ObjectBox annotation processor.

In your project’s build.gradle file after the java plugin, add the necessary compiler argument:

tasks.withType(JavaCompile) {
options.compilerArgs += [ "-Aobjectbox.modelPath=$projectDir/schemas/objectbox.json" ]
}

Optional: Enable Debug Mode

You can enable debug output for the plugin and for the annotation processor if you encounter issues while setting up your project.

Just add the necessary options in your project’s build.gradle file after the java and io.objectbox plugin

// enable debug output for plugin
objectbox {
debug true
}
// enable debug output for annotation processor
tasks.withType(JavaCompile) {
options.compilerArgs += [ "-Aobjectbox.debug=true" ]
}

Add Entity Classes

You must create at least one class annotated with @Entity to use ObjectBox. If you don’t know yet how to do this, learn here how to create and annotate entity classes.

The following code snippet shows how a simple entity class might look like:

@Entity
public class Note {
@Id
public long id;
public String text;
public String comment;
public Date date;
public Note(long id, String text, String comment, Date date) {
this.id = id;
this.text = text;
this.comment = comment;
this.date = date;
}
public Note() {
}
}

Build BoxStore

To get a Box for saving your entities you need to build a BoxStore first. After creating your entity classes and building your project, e.g. by running gradlew build, the class MyObjectBox will be generated. Use MyObjectBox.builder() to build your BoxStore.

This code snippet demonstrates a simple program that builds a BoxStore and saves a Note entity object:

public static void main(String[] args) {
BoxStore store = MyObjectBox.builder().name("objectbox-notes-db").build();
Box<Note> box = store.boxFor(Note.class);
String text = args.length > 0 ? String.join(" ", args) : "No text given";
box.put(new Note(text));
System.out.println(box.count() + " notes in ObjectBox database:");
for (Note note : box.getAll()) {
System.out.println(note);
}
store.close();
}

You can use the name(String) method of the builder to change the directory name your database files are stored in. See the BoxStoreBuilder documentation for more configuration options.

Building Unit Tests

In your project’s build.gradle file, add the JUnit testing framework to your test dependencies:

dependencies {
testCompile 'junit:junit:4.12'
}

You create your unit test classes as usual under module-name/src/test/java/. To use ObjectBox in your test methods you need to build a BoxStore instance using the generated MyObjectBox class of your project. You can use the directory(File) method on the BoxStore builder to ensure the test database is stored in a specific folder on your machine. To start with a clean database for each test you can delete the existing database using BoxStore.deleteAllFiles(File).

The following example shows how you could implement a unit test class that uses ObjectBox:

public class NoteTest {
private File boxStoreDir;
private BoxStore store;
@Before
public void setUp() throws IOException {
// store the database in the systems temporary files folder
File tempFile = File.createTempFile("object-store-test", "");
// ensure file does not exist so builder creates a directory instead
tempFile.delete();
boxStoreDir = tempFile;
store = MyObjectBox.builder()
// add directory flag to change where ObjectBox puts its database files
.directory(boxStoreDir)
// optional: add debug flags for more detailed ObjectBox log output
.debugFlags(DebugFlags.LOG_QUERIES | DebugFlags.LOG_QUERY_PARAMETERS)
.build();
}
@After
public void tearDown() throws Exception {
if (store != null) {
store.close();
store.deleteAllFiles();
}
}
@Test
public void testPutAndGet() {
Box<Note> box = store.boxFor(Note.class);
assertEquals(...);
}
}

To help diagnose issues you can enable log output for ObjectBox actions, such as queries, by specifying one or more debug flags when building BoxStore.