commonMain.io.realm.kotlin.serializers.RealmKSerializers.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of library-base-jvm Show documentation
Show all versions of library-base-jvm Show documentation
Library code for Realm Kotlin. This artifact is not supposed to be consumed directly, but through 'io.realm.kotlin:gradle-plugin:1.11.1' instead.
/*
* Copyright 2023 Realm Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.realm.kotlin.serializers
import io.realm.kotlin.ext.asRealmObject
import io.realm.kotlin.ext.toRealmDictionary
import io.realm.kotlin.ext.toRealmList
import io.realm.kotlin.ext.toRealmSet
import io.realm.kotlin.internal.asBsonDateTime
import io.realm.kotlin.internal.asRealmInstant
import io.realm.kotlin.types.MutableRealmInt
import io.realm.kotlin.types.RealmAny
import io.realm.kotlin.types.RealmAny.Type
import io.realm.kotlin.types.RealmDictionary
import io.realm.kotlin.types.RealmInstant
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.types.RealmObject
import io.realm.kotlin.types.RealmSet
import io.realm.kotlin.types.RealmUUID
import kotlinx.serialization.Contextual
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.SetSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.modules.SerializersModule
import org.mongodb.kbson.BsonBinary
import org.mongodb.kbson.BsonBinarySubType
import org.mongodb.kbson.BsonDateTime
import org.mongodb.kbson.BsonObjectId
import org.mongodb.kbson.Decimal128
/**
* KSerializer implementation for [RealmList]. Serialization is done as a generic list structure,
* whilst deserialization is done into an unmanaged [RealmList].
*
* It supports any serializable type as a type argument.
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmListKSerializer::class)
* var myList: RealmList = realmListOf()
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmListKSerializer::class)
*
* class Example : RealmObject {
* var myList: RealmList = realmListOf()
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public class RealmListKSerializer(elementSerializer: KSerializer) :
KSerializer> {
private val serializer = ListSerializer(elementSerializer)
override val descriptor: SerialDescriptor =
serializer.descriptor
override fun deserialize(decoder: Decoder): RealmList =
serializer.deserialize(decoder).toRealmList()
override fun serialize(encoder: Encoder, value: RealmList) {
serializer.serialize(encoder, value)
}
}
/**
* KSerializer implementation for [RealmSet]. Serialization is done as a generic list structure,
* whilst deserialization is done into an unmanaged [RealmSet].
*
* It supports any serializable type as a type argument.
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmSetKSerializer::class)
* var mySet: RealmSet = realmSetOf()
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmSetKSerializer::class)
*
* class Example : RealmObject {
* var mySet: RealmSet = realmSetOf()
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public class RealmSetKSerializer(elementSerializer: KSerializer) : KSerializer> {
private val serializer = SetSerializer(elementSerializer)
override val descriptor: SerialDescriptor =
serializer.descriptor
override fun deserialize(decoder: Decoder): RealmSet =
serializer.deserialize(decoder).toRealmSet()
override fun serialize(encoder: Encoder, value: RealmSet) {
serializer.serialize(encoder, value)
}
}
/**
* KSerializer implementation for [RealmDictionary]. Serialization is done as a generic map structure,
* whilst deserialization is done into an unmanaged [RealmDictionary].
*
* It supports any serializable type as a type argument.
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmDictionaryKSerializer::class)
* var myDictionary: RealmDictionary = realmDictionaryOf()
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmDictionaryKSerializer::class)
*
* class Example : RealmObject {
* var myDictionary: RealmDictionary = realmDictionaryOf()
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public class RealmDictionaryKSerializer(elementSerializer: KSerializer) :
KSerializer> {
private val serializer = MapSerializer(String.serializer(), elementSerializer)
override val descriptor: SerialDescriptor =
serializer.descriptor
override fun deserialize(decoder: Decoder): RealmDictionary =
serializer.deserialize(decoder).toRealmDictionary()
override fun serialize(encoder: Encoder, value: RealmDictionary) {
serializer.serialize(encoder, value)
}
}
/**
* KSerializer implementation for [RealmInstant]. It is serialized as a [BsonDateTime], to allow direct
* usage on Mongodb function calls, and deserialized as an unmanaged [RealmInstant].
*
* Warning: because [RealmInstant] and [BsonDateTime] have different precision the serialization will
* lose precision as nanoseconds get truncated to milliseconds.
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmInstantKSerializer::class)
* var myInstant: RealmInstant = RealmInstant.now()
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmInstantKSerializer::class)
*
* class Example : RealmObject {
* var myInstant: RealmInstant = RealmInstant.now()
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public object RealmInstantKSerializer : KSerializer {
private val serializer = BsonDateTime.serializer()
override val descriptor: SerialDescriptor = serializer.descriptor
override fun deserialize(decoder: Decoder): RealmInstant =
decoder.decodeSerializableValue(serializer).asRealmInstant()
override fun serialize(encoder: Encoder, value: RealmInstant) {
encoder.encodeSerializableValue(
serializer = serializer,
value = value.asBsonDateTime()
)
}
}
/**
* KSerializer implementation for [RealmAny]. Serialization is done as a specific map structure
* that represents the a union type with all possible value types:
*
* ```
* realmAny:
* type: [INT, BOOL, STRING, BINARY, TIMESTAMP, FLOAT, DOUBLE, DECIMAL128, OBJECT_ID, UUID, OBJECT]
* int: Long?
* bool: Boolean?
* string: String?
* binary: ByteArray?
* instant: RealmInstant?
* float: Float?
* double: Double?
* decimal128: Decimal128?
* objectId: ObjectId?
* uuid: RealmUUID?
* realmObject: RealmObject?
* ```
*
* Deserialization is done with an unmanaged [RealmAny].
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmAnyKSerializer::class)
* var myInstant: RealmAny = RealmAny.create("hello world")
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmAnyKSerializer::class)
*
* class Example : RealmObject {
* var myInstant: RealmAny = RealmAny.create("hello world")
* }
* ```
*
* Serialization of [RealmAny] instances containing [RealmObject] require of a [SerializersModule]
* mapping such objects to the polymorphic [RealmObject] interface:
*
* ```
* val json = Json {
* serializersModule = SerializersModule {
* polymorphic(RealmObject::class) {
* subclass(SerializableSample::class)
* }
* }
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public object RealmAnyKSerializer : KSerializer {
/**
* This class represents a union type of all possible RealmAny types. We cannot write a regular
* serializer because we need to be able to resolve the serializer for a RealmObject in runtime,
* and the only way to do it is through kserialization internal functions.
*/
@Serializable
private class SerializableRealmAny {
lateinit var type: String
var int: Long? = null
var bool: Boolean? = null
var string: String? = null
var binary: ByteArray? = null
@Serializable(RealmInstantKSerializer::class)
var instant: RealmInstant? = null
var float: Float? = null
var double: Double? = null
var decimal128: Decimal128? = null
var objectId: BsonObjectId? = null
@Serializable(RealmUUIDKSerializer::class)
var uuid: RealmUUID? = null
var realmObject: RealmObject? = null
@Contextual
var set: RealmSet? = null
@Contextual
var list: RealmList? = null
@Contextual
var dictionary: RealmDictionary? = null
}
private val serializer = SerializableRealmAny.serializer()
override val descriptor: SerialDescriptor = serializer.descriptor
@Suppress("ComplexMethod")
override fun deserialize(decoder: Decoder): RealmAny {
return decoder.decodeSerializableValue(serializer).let {
when (Type.valueOf(it.type)) {
Type.INT -> RealmAny.create(it.int!!.toLong())
Type.BOOL -> RealmAny.create(it.bool!!)
Type.STRING -> RealmAny.create(it.string!!)
Type.BINARY -> RealmAny.create(it.binary!!)
Type.TIMESTAMP -> RealmAny.create(it.instant!!)
Type.FLOAT -> RealmAny.create(it.float!!)
Type.DOUBLE -> RealmAny.create(it.double!!)
Type.DECIMAL128 -> RealmAny.create(it.decimal128!!)
Type.OBJECT_ID -> RealmAny.create(it.objectId!!)
Type.UUID -> RealmAny.create(it.uuid!!)
Type.OBJECT -> RealmAny.create(it.realmObject!!)
Type.LIST -> RealmAny.create(it.list!!)
Type.DICTIONARY -> RealmAny.create(it.dictionary!!)
}
}
}
@Suppress("ComplexMethod")
override fun serialize(encoder: Encoder, value: RealmAny) {
encoder.encodeSerializableValue(
serializer,
SerializableRealmAny().apply {
type = value.type.name
when (value.type) {
Type.INT -> int = value.asLong()
Type.BOOL -> bool = value.asBoolean()
Type.STRING -> string = value.asString()
Type.BINARY -> binary = value.asByteArray()
Type.TIMESTAMP -> instant = value.asRealmInstant()
Type.FLOAT -> float = value.asFloat()
Type.DOUBLE -> double = value.asDouble()
Type.DECIMAL128 -> decimal128 = value.asDecimal128()
Type.OBJECT_ID -> objectId = BsonObjectId(
value.asObjectId().toByteArray()
)
Type.UUID -> uuid = value.asRealmUUID()
Type.OBJECT -> realmObject = value.asRealmObject()
Type.LIST -> list = value.asList()
Type.DICTIONARY -> dictionary = value.asDictionary()
}
}
)
}
}
/**
* KSerializer implementation for [RealmUUID]. Serialized as a [BsonBinary] with subtype
* [BsonBinarySubType.UUID_STANDARD], and deserialized as an unmanaged [RealmUUID].
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(RealmUUIDKSerializer::class)
* var myUUID: RealmUUID = RealmUUID.create()
* }
* ```
* or per file:
* ```
* @file:UseSerializers(RealmUUIDKSerializer::class)
*
* class Example : RealmObject {
* var myUUID: RealmUUID = RealmUUID.create()
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public object RealmUUIDKSerializer : KSerializer {
private val serializer = BsonBinary.serializer()
override val descriptor: SerialDescriptor = serializer.descriptor
override fun deserialize(decoder: Decoder): RealmUUID =
RealmUUID.from(decoder.decodeSerializableValue(serializer).data)
override fun serialize(encoder: Encoder, value: RealmUUID) {
encoder.encodeSerializableValue(
serializer = serializer,
value = BsonBinary(BsonBinarySubType.UUID_STANDARD, value.bytes)
)
}
}
/**
* KSerializer implementation for [MutableRealmInt]. Serialization is done with a primitive long value,
* whilst deserialization is done with an unmanaged [MutableRealmInt].
*
* The serializer must be registered per property:
* ```
* class Example : RealmObject {
* @Serializable(MutableRealmIntKSerializer::class)
* var myMutableRealmInt: MutableRealmInt = MutableRealmInt.create(0)
* }
* ```
* or per file:
* ```
* @file:UseSerializers(MutableRealmIntKSerializer::class)
*
* class Example : RealmObject {
* var myMutableRealmInt: MutableRealmInt = MutableRealmInt.create(0)
* }
* ```
*
* Adding the following code snippet to a Kotlin file would conveniently register any field using a
* Realm datatype to its correspondent serializer:
*
* ```
* @file:UseSerializers(
* RealmListKSerializer::class,
* RealmSetKSerializer::class,
* RealmAnyKSerializer::class,
* RealmInstantKSerializer::class,
* MutableRealmIntKSerializer::class,
* RealmUUIDKSerializer::class
* )
* ```
*
* Serializers for all Realm data types can be found in [io.realm.kotlin.serializers].
*/
public object MutableRealmIntKSerializer : KSerializer {
override val descriptor: SerialDescriptor = Long.serializer().descriptor
override fun deserialize(decoder: Decoder): MutableRealmInt =
MutableRealmInt.create(decoder.decodeLong())
override fun serialize(encoder: Encoder, value: MutableRealmInt) {
encoder.encodeLong(value.toLong())
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy