The Realm Kotlin SDK supports Kotlin Serialization. You can serialize specific Realm data types using stable serializers, or user-defined classes with an experimental full-document serialization API.
The Realm Kotlin SDK provides serializers for the following data types for KSerializer:
Realm Data Type
KSerializer for Type
MutableRealmInt
MutableRealmIntKSerializer::class
RealmAny
RealmAnyKSerializer::class
RealmDictionary
RealmDictionaryKSerializer::class
RealmInstant
RealmInstantKSerializer::class
RealmList
RealmListKSerializer::class
RealmSet
RealmSetKSerializer::class
RealmUUID
RealmUUIDKSerializer::class
The serializers are located in io.realm.kotlin.serializers
.
For examples of how Realm serializes the different data types, refer to Serialization Output Examples.
Deserializing Realm data types generates unmanaged data instances.
You can register a serializer for a specific property. Use the @Serializable
annotation to bind to a specific Realm data type serializer.
class Frog : RealmObject { var name: String = "" @Serializable(RealmListKSerializer::class) var favoritePonds: RealmList<String> = realmListOf()}
You can register a serializer for all occurrences of that type within a file by adding the declaration to the top of the file:
@file:UseSerializers(RealmSetKSerializer::class)import io.realm.kotlin.ext.realmSetOfimport io.realm.kotlin.serializers.RealmSetKSerializerimport io.realm.kotlin.types.RealmSetimport kotlinx.serialization.UseSerializers
Then, any objects that have properties of that type within the file can use the serializer without individually registering it:
class Movie : RealmObject { var movieTitle: String = "" var actors: RealmSet<String> = realmSetOf()}class TVSeries : RealmObject { var seriesTitle: String = "" var episodeTitles: RealmSet<String> = realmSetOf()}
To automatically bind all Realm types to their serializers, you can add a snippet containing all serializers to the top of a file:
@file:UseSerializers( MutableRealmIntKSerializer::class, RealmAnyKSerializer::class, RealmDictionaryKSerializer::class, RealmInstantKSerializer::class, RealmListKSerializer::class, RealmSetKSerializer::class, RealmUUIDKSerializer::class)
These examples illustrate how the different Realm data types serialize using a JSON encoder:
Realm Data Type
Serialization Type and Example
MutableRealmInt
Serializes using a regular integer value.
MutableRealmInt.create(35)
serializes to 35
RealmAny
Serializes using a map containing a union of all values and its type.
RealmAny.create("hello world")
serializes to {"type": "STRING", "string": "hello world"}
RealmAny.create(20)
serializes to {"type": "INT", "int": 20}
RealmDictionary
Serializes using a generic list.
realmDictionaryOf("hello" to "world")
serializes to {"hello": "world"}
RealmInstant
Serializes as a BsonDateTime
.
RealmInstant.now()
serializes to {"$date": {"$numberLong": "<millis>"}}
RealmList
Serializes using a generic list.
realmListOf("hello", world)
serializes to ["hello", "world"]
RealmSet
Serializes using a generic list.
realmSetOf("hello", world)
serializes to ["hello", "world"]
BsonObjectId or ObjectId
Serializes as a BsonObjectId
.
ObjectId.create()
serializes to {"$oid": <ObjectId bytes as 24-character, big-endian hex string>}
RealmUUID
Serializes as a BsonBinary
.
RealmUUID.random()
serializes to { "$binary": {"base64": "<payload>", "subType": "<t>"}}
RealmObject
Serializes using the polymorphic setup defined by the user. Do this via the SerializersModule:
val json = Json { serializersModule = SerializersModule { polymorphic(RealmObject::class) { subclass(SerializableSample::class) } }}
New in version 1.9.0.
Realm Kotlin SDK APIs that communicate directly with MongoDB Atlas use EJSON encoding. The SDK offers two types of EJSON encoders:
A limited but stable encoder
An experimental encoder that offers full document serialization
The APIs that use these encoders include:
App Services Function calls
Credentials with custom function authentication
User profile and custom user data
The Realm Kotlin SDK's EJSON serialization support depends on the official Kotlin Serialization library. You must add Kotlin Serialization to your project. Use the same version used in your Realm Kotlin SDK version. Refer to the Version Compatibility Matrix in the realm-kotlin GitHub repository for information about the supported dependencies of each version.
The @Serializable
annotation in the following examples comes from the Kotlin Serialization framework.
The stable encoder does not support user-defined classes. You can use these argument types with the stable encoder:
Primitives
BSON
MutableRealmInt
RealmUUID
ObjectId
RealmInstant
RealmAny
Array
Collection
Map
To return a collection or map, you can use BsonArray
or BsonDocument
.
You can call a Function using the stable encoder with a valid argument type, and deserialize the result.
In this example, we call the getMailingAddress
Function with two string arguments, and get the result as a BsonDocument
:
val address = user.functions.call<BsonDocument>("getMailingAddress", "Bob", "Smith")assertEquals(address["street"], BsonString("123 Any Street"))
You can create a Credential
for use with custom function authentication using the stable encoder as either a map or a BsonDocument
:
val credentials = Credentials.customFunction( mapOf( "userId" to 500, "password" to "securePassword" ))val bsonCredentials = Credentials.customFunction( BsonDocument( mapOf( "userId" to BsonInt32(500), "password" to BsonString("securePassword") ) ))app.login(credentials)
You can access a user profile or custom user data using the stable encoder as a BsonDocument
:
val user = app.currentUser!!val userProfile = user.profileAsBsonDocument()assertEquals(userProfile["email"], BsonString("my.email@example.com"))
val user = app.currentUser!!val customUserData = user.customDataAsBsonDocument()assertEquals(BsonString("blue"), customUserData?.get("favoriteColor"))
The full-document encoder enables you to serialize and deserialize user-defined classes. You can define and use custom KSerializers for your type with Atlas features that communicate directly with MongoDB Atlas using EJSON encoding. The full-document encoder supports contextual serializers.
Important This is experimentalThe current implementation of full document serialization is experimental. Calling these APIs when your project uses a different version of Kotlin Serialization than Realm's dependency causes undefined behavior. Refer to the Version Compatibility Matrix in the realm-kotlin GitHub repository for information about the supported dependencies of each version.
To use this feature, add one or more of the following imports to your file as relevant:
import kotlinx.serialization.Serializableimport io.realm.kotlin.annotations.ExperimentalRealmSerializerApiimport org.mongodb.kbson.ExperimentalKBsonSerializerApiimport kotlinx.serialization.modules.SerializersModuleimport io.realm.kotlin.serializers.RealmListKSerializer
When you use serialization in the Realm Kotlin SDK, you can define a serializer in one of two ways:
Add the @Serializable
annotation to a class
Define a custom KSerializer for your type, and pass it to the relevant API
@Serializableclass Person( val firstName: String, val lastName: String)
You can set a custom EJSON serializer for your app in the AppConfiguration
, as in a case where you want to use a contextual serializer:
@Serializableclass Frogger( val name: String, @Contextual val date: LocalDateTime)AppConfiguration.Builder(FLEXIBLE_APP_ID) .ejson( EJson( serializersModule = SerializersModule { contextual(DateAsIntsSerializer) } ) ) .build()
Because the full-document serialization API is experimental, you must add the relevant @OptIn
annotations for the APIs you use.
@OptIn(ExperimentalRealmSerializerApi::class)
You can call a Function using the experimental API with arguments or return types that use custom serializers.
In this example, we call the getMailingAddressForPerson
Function with a serialized Person
object, and get the result as a deserialized Address
object:
@Serializableclass Address( val street: String, val city: String, val state: String, val country: String, val postalCode: String)@Serializableclass Person( val firstName: String, val lastName: String)
val address = user.functions.call<Address>("getMailingAddressForPerson"){ add(Person("Bob", "Smith"))}assertEquals(address.street, "123 Any Street")
Tip
Atlas Function calls for the stable serializer and the experimental API serializer share the same method name. When invoking a function with no parameters, you must provide an empty block in the instruction for the experimental API.
val color = user.functions.call<PersonalFavorites>("favouriteColor") {}
You can define a custom serializer for custom function authentication using the experimental API:
@Serializableclass CustomUserCredential( val userId: Int, val password: String)
And use it when creating a custom function credential:
val credentials = Credentials.customFunction( CustomUserCredential( userId = 500, password = "securePassword" ))app.login(credentials)
Define a custom serializer for user profile or custom data:
@Serializableclass UserProfile( val email: String)
@Serializableclass UserCustomData( val favoriteColor: String)
And use the custom serializer when accessing the user profile or custom user data:
val user = app.currentUser!!val userProfile = user.profile<UserProfile>()assertEquals(userProfile.email, "my.email@example.com")
val user = app.currentUser!!val customUserData = user.customData<UserCustomData>()assertEquals("blue", customUserData!!.favoriteColor)
Serialization methods used by libraries that depend on reflection, such as GSON do not work with the SDK by default.
This is because the SDK compiler plugin injects a hidden field into object models, prefixed with io_realm_kotlin_
. The SDK uses this hidden field to manage internal object state. Any library that relies on fields instead of getters and setters needs to ignore this hidden field.
To use the SDK with external libraries such as GSON, exclude the hidden fields from serialization using a prefix match:
var gson: Gson = GsonBuilder() .setExclusionStrategies(object: ExclusionStrategy { override fun shouldSkipField(f: FieldAttributes?): Boolean = f?.name?.startsWith("io_realm_kotlin_") ?: false override fun shouldSkipClass(clazz: Class<*>?): Boolean = false }) .create()
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4