Android: Model Layer

2015-04-06

Having typed models in your Android apps can greatly improve efficiency and productivity.

Currently, the Couchbase Mobile Android SDK does not provide an abstraction layer over revisions and documents and it can be cumbersome to have to deal with Maps everywhere.

Couchbase Lite Android uses Jackson internally to marshal/un-marshal JSON.

In this post, we’ll explore how to use it to convert the document properties (Map<String, Object>) to POJO classes and vice versa.

To keep things extensible, we’ll define a ModelHelper class with static methods.

Quickstart

As an example, let’s consider a Task model with a title, author and date. In JSON, it looks like this:

{
     "_id": "123",
     "title": "A simple title",
     "user_id": 987,
     "date": "2015-04-06T22:22:09.414Z"
}

From POJO to Map<String, Object>

Create a new Task.java class with the following fields:

@JsonIgnoreProperties(ignoreUnknown = true)
public class Task {

    @JsonProperty(value = "_id")
    private String documentId;

    private String title;

    @JsonProperty(value = "user_id")
    private int userId;

    private Date createAt;

    // getters, setters...
}

Couchbase Lite documents store additional metadata such as the revision id (_rev) and in this case we don’t need it on the model class. We use the @JsonIgnoreProperties annotation to ignore the JSON keys we haven’t specified here.

We can provide the JSON key as well as a custom property name in our models with the @JsonProperty annotation.

The ModelHelper class

Now let’s create a new class called ModelHelper.java with a static method to persist a Task model instance as a Couchbase document:

public class ModelHelper {

    public static void save(Database database, Object object) {
        ObjectMapper m = new ObjectMapper();
        Map<String, Object> props = m.convertValue(object, Map.class);
        String id = (String) props.get("_id");

        Document document;
        if (id == null) {
            document = database.createDocument();
        } else {
            document = database.getExistingDocument(id);
            if (document == null) {
                document = database.getDocument(id);
            } else {
                props.put("_rev", document.getProperty("_rev"));
            }
        }

        try {
            document.putProperties(props);
        } catch (CouchbaseLiteException e) {
            e.printStackTrace();
        }
    }

}

We can use it in our app like so:

Task task = new Task();
task.setDocumentId("123");
task.setTitle("A simple title");
task.setUserId(987);

ModelHelper.save(database, task);

The save method persists new documents as well as document updates. If there isn’t an _id property in the JSON, we can create a new document. Otherwise we check if the document with the _id passed in exists in the database. If it does we replace the _rev property with the latest one and call putProperties to update the document.

From Map<String, Object> to POJO

Now we might have queries running in our app and we’d like to convert each document to a Task model instance. We can use the same convertValue method from the Jackson API to do so:

public class ModelHelper {

    ...

    public static <T> T modelForDocument(Document document, Class<T> aClass) {
        ObjectMapper m = new ObjectMapper();
        return m.convertValue(document.getProperties(), aClass);
    }

}

Now you can create a task model instance from a document:

Document doc = database.getDocument("123");
Task task = ModelHelper.modelForDocument(doc, Task.class);

Conclusion

Using Jackson that is already a dependency of Couchbase Lite Android, it’s very easy to build your own model helper class to make the model <-> document conversion easier.

I’d love to hear your feedback on making this process easier for developing Android apps.

Read more:

comments powered by Disqus