简体   繁体   English

ReamList 和 List 的 Kotlin 序列化序列化器

[英]Kotlin serialization serializer for ReamList and List

I just tried to use Kotlin serialization library to replace Gson however I am having issues using it for RealmList in my model.我只是尝试使用 Kotlin 序列化库来替换 Gson 但是我在 model 中将它用于 RealmList 时遇到问题。 Any help will be appreciated.任何帮助将不胜感激。 Am getting error kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.realm.RealmList我收到错误kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.realm.RealmList

I have my data class like this我有这样的数据 class

data class Person(
var name: String = "", 
var social : RealmList<Social> = null, 
var id: String = "") 

and my social data class is我的社交数据 class 是

data class Social(
var name: String = "", 
var category : String = "", 
var id: String = "")

and this is my retrofit builder这是我的 retrofit 构建器

fun provideRetrofit(okHttpClient: OkHttpClient, urlProvider :
    URLProvider): Retrofit {
    val contentType = MediaType.get("application/json")
    return Retrofit.Builder()
        .baseUrl(urlProvider.getApiBaseUrl()!!)
        .addConverterFactory(Json.asConverterFactory(contentType))
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(okHttpClient)
        .build()
}

am using Retrofit adapter specific for Kotlin serialisation and my retrofit call我正在使用 Retrofit 适配器专用于 Kotlin 序列化和我的 retrofit 调用

override fun loadPersons(): Single<Person> {
    return communicationContext.personApi
        .getPersonsObservable()
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .doOnError {
            Log.e(TAG, "Load error $it")
        }
        .doOnSuccess {
            Log.e(TAG, "Success size ${it.size}")
        }
}

You have to build a custom RealmListSerializer in order to make it work.您必须构建一个自定义 RealmListSerializer 才能使其工作。

Under the current version 1.0.1 of kotlinx.serialization there is no ListSerializer you might extend from.在 kotlinx.serialization 的当前版本 1.0.1 下,没有您可以扩展的 ListSerializer。 This means you have to build your own one from scratch.这意味着您必须从头开始构建自己的。

Luckily some sort of ListSerializer exists in the library, but it is marked as internal and thus not accessible to you in code.幸运的是,库中存在某种 ListSerializer,但它被标记为内部的,因此您无法在代码中访问。 Nevertheless I was able to write a serializer based on the ones found in the library.尽管如此,我还是能够根据库中找到的序列化程序编写序列化程序。 Everything is based off of ArrayListSerializer and its parent classes.一切都基于ArrayListSerializer及其父类。

CAUTION.警告。 These classes are marked as experimental, It is very likely that their implementation may change.这些类被标记为实验性的,它们的实现很可能会改变。 which will break all behaviour.这将破坏所有行为。 Errors are to be expected.错误是意料之中的。

The classes copied from are ArrayListSerializer , ListLikeSerializer , AbstractCollectionSerializer in package kotlinx.serialization.internal.CollectionSerializer.kt and ArrayClassDesc , ListLikeDescriptor in package kotlinx.serialization.internal.CollectionDescriptors.kt . The classes copied from are ArrayListSerializer , ListLikeSerializer , AbstractCollectionSerializer in package kotlinx.serialization.internal.CollectionSerializer.kt and ArrayClassDesc , ListLikeDescriptor in package kotlinx.serialization.internal.CollectionDescriptors.kt .

Here is the code: RealmListSerializer.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"

}

Afterwards you can use this class inside your RealmObject classes like this:之后,您可以在RealmObject类中使用此 class ,如下所示:

@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()

Alternatively if you use a lot of RealmList s inside one of your RealmObejct s you can apply this (and other serializers) to the whole file.或者,如果您在其中一个RealmObejct中使用大量RealmList ,则可以将其(和其他序列化程序)应用于整个文件。

@file:UseSerializers(RealmListSerializer::class)

Again, please use with caution.再次,请谨慎使用。 The classes this is created from are still experimental and may change at any time without notice.从中创建的类仍处于试验阶段,可能随时更改,恕不另行通知。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM