Overview

Ebean provides @DbJson and @DbJsonB for mapping properties as JSON documents into Postgres JSON, Postgres JSONB, CLOB, VARCHAR or BLOB.

Both Postgres and Oracle (and shortly MySql) provide functions/expressions for querying and manipulating the JSON.

Ebean also has ElasticSearch integration so even without the built in database support we can use that integration to effectively replicate to ElasticSearch and use it to search our data.

Mixing structured and unstructured

What these capabilities do is enable designers/developers to mix unstructured (or semi-structured) document content with our typically highly structured data.

An example use case might be storing 'user preferences' where the data naturally comes in as JSON, has potentially deep nesting and where we only need limited queries/expressions on the document attributes. In this type of case the use of unstructured document storage as JSON can be a good fit.

Mapping simple types

If the mapping is to String, Long or Map<String,Object> types then Ebean will use it's built in JSON support to handle the marshalling to/from JSON.

@DbJsonB
Map<String,Object> content;

@DbJsonB
List<String> contents;

With these types note that Ebean will use ModifyAware collections so that it knows if the property is dirty and needs to be included in an update. If the type is not ModifyAware then it must be treated as dirty and included in an update.

Mapping with Jackson ObjectMapper

If the type mapped is not one of String, Long or Map<String,Object> types then Ebean will use Jackson ObjectMapper to handle the marshalling to/from JSON. In this case jackson-databind becomes a required dependency.

// Jackson ObjectMapper used here
@DbJsonB
Map<String,SomePojo> content;

// Jackson ObjectMapper used here
@DbJsonB
SomePojo content;

Note that when we use Jackson for marshalling the property type is not ModifyAware and that means that it must be treated as dirty and included in updates. It will only be included in updates if the property is actually loaded of course and so if you know a use case will not update the content it can be worth while to not load it in the first place (with the additional benefit that it won't be automatically included in the update).

ServerConfig

An ObjectMapper instance can be configured on ServerConfig via setObjectMapper(). If an ObjectMapper is not specified in this way an instance will be created for use by Ebean (If Jackson ObjectMapper is detected in the classpath).

Fallback mapping

When Postgres is not used then fallback is to store JSON into VARCHAR, CLOB or BLOB database types. If the length attribute is specified like @DbJson(length=1000) or @DbJsonB(length=1000) then VARCHAR is the fallback type and the length defined is the length of the varchar column definition.

// fallback to store in VARCHAR(800)
@DbJson(length=800)
Map<String,Object> content;

The storage can be explicitly defined using the storage attribute.

// explicitly store using BLOB
@DbJson(storage = DbJsonType.BLOB)
Map<String,Object> content;

The default fallback for JSON and JSONB types is CLOB and this is used when both the length and storage attributes are not defined.

Query expressions

Refer to json-in-db documentation for details on the query expressions and how those translate for both Postgres and Oracle expressions.