您必须构建一个自定义 RealmListSerializer 才能使其工作。
在 kotlinx.serialization 的当前版本 1.0.1 下,没有您可以扩展的 ListSerializer。这意味着您必须从头开始构建自己的。
幸运的是,库中存在某种 ListSerializer,但它被标记为内部的,因此您无法在代码中访问。尽管如此,我还是能够根据库中找到的序列化程序编写序列化程序。一切都基于ArrayListSerializer
其父类。
警告!这些类被标记为实验性的。它们的实现很可能会改变,这将破坏所有行为。错误是意料之中的。
从中复制的类是ArrayListSerializer
, ListLikeSerializer
, AbstractCollectionSerializer
in packagekotlinx.serialization.internal.CollectionSerializer.kt
和ArrayClassDesc
, ListLikeDescriptor
in package kotlinx.serialization.internal.CollectionDescriptors.kt
。
这是代码:RealmListSerializer.kt
import io.realm.RealmList
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.SerialKind
import kotlinx.serialization.descriptors.StructureKind
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializer(forClass = RealmList::class)
class RealmListSerializer<E>(private val dataSerializer : KSerializer<E>) : KSerializer<RealmList<E>> {
fun builder(): ArrayList<E> = arrayListOf()
private fun ArrayList<E>.toResult() : RealmList<E> {
val realmList = RealmList<E>()
for (i in this) {
realmList.add(i)
}
return realmList
}
private fun merge(decoder: Decoder): RealmList<E> {
val builder = builder()
val startIndex = builder.size
val compositeDecoder = decoder.beginStructure(descriptor)
if (compositeDecoder.decodeSequentially()) {
readAll(compositeDecoder, builder, startIndex, readSize(compositeDecoder, builder))
} else {
while (true) {
val index = compositeDecoder.decodeElementIndex(descriptor)
if (index == CompositeDecoder.DECODE_DONE) break
readElement(compositeDecoder, startIndex + index, builder)
}
}
compositeDecoder.endStructure(descriptor)
return builder.toResult()
}
override val descriptor : SerialDescriptor = RealmListDescriptor(dataSerializer.descriptor)
override fun serialize(encoder : Encoder, value : RealmList<E>) {
val size = value.size
val composite = encoder.beginCollection(descriptor, size)
val iterator = value.iterator()
for (index in 0 until size)
composite.encodeSerializableElement(descriptor, index, dataSerializer, iterator.next())
composite.endStructure(descriptor)
}
override fun deserialize(decoder : Decoder) : RealmList<E> = merge(decoder)
private fun readSize(decoder: CompositeDecoder, builder: ArrayList<E>): Int {
val size = decoder.decodeCollectionSize(descriptor)
builder.ensureCapacity(size)
return size
}
private fun readElement(decoder: CompositeDecoder, index: Int, builder: ArrayList<E>, checkIndex: Boolean = true) {
builder.add(index, decoder.decodeSerializableElement(descriptor, index, dataSerializer))
}
private fun readAll(decoder: CompositeDecoder, builder: ArrayList<E>, startIndex: Int, size: Int) {
require(size >= 0) { "Size must be known in advance when using READ_ALL" }
for (index in 0 until size)
readElement(decoder, startIndex + index, builder, checkIndex = false)
}
}
class RealmListDescriptor(private val elementDescriptor : SerialDescriptor) : SerialDescriptor {
override val kind: SerialKind get() = StructureKind.LIST
override val elementsCount: Int = 1
override fun getElementName(index: Int): String = index.toString()
override fun getElementIndex(name: String): Int =
name.toIntOrNull() ?: throw IllegalArgumentException("$name is not a valid list index")
override fun isElementOptional(index: Int): Boolean {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return false
}
override fun getElementAnnotations(index: Int): List<Annotation> {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return emptyList()
}
override fun getElementDescriptor(index: Int): SerialDescriptor {
require(index >= 0) { "Illegal index $index, $serialName expects only non-negative indices"}
return elementDescriptor
}
override val serialName : String
get() = "RealmListSerializer"
}
之后你可以像这样在你的RealmObject
类中使用这个类:
@Serializable
open class Person(
@PrimaryKey var id: Long = 0,
var name: String = "",
var age: Int = 0,
@Serializable(with = RealmListSerializer::class)
var dogs: RealmList<Dog> = RealmList()
): RealmObject()
RealmList
或者,如果您在其中一个 s 中使用大量s RealmObejct
,则可以将其(和其他序列化程序)应用于整个文件。
@file:UseSerializers(RealmListSerializer::class)
再次,请谨慎使用。从中创建的类仍处于试验阶段,可能随时更改,恕不另行通知。