1

我只是尝试使用 Kotlin 序列化库来替换 Gson,但是在我的模型中将它用于 RealmList 时遇到问题。任何帮助将不胜感激。我收到错误 kotlinx.serialization.SerializationException: Can't locate argument-less serializer for class io.realm.RealmList

我有这样的数据类

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

我的社交数据类是

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

这是我的改造建造者

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

我正在使用专门用于 Kotlin 序列化的改造适配器和我的改造电话

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}")
        }
}
4

1 回答 1

1

您必须构建一个自定义 RealmListSerializer 才能使其工作。

在 kotlinx.serialization 的当前版本 1.0.1 下,没有您可以扩展的 ListSerializer。这意味着您必须从头开始构建自己的。

幸运的是,库中存在某种 ListSerializer,但它被标记为内部的,因此您无法在代码中访问。尽管如此,我还是能够根据库中找到的序列化程序编写序列化程序。一切都基于ArrayListSerializer其父类。

警告!这些类被标记为实验性的。它们的实现很可能会改变,这将破坏所有行为。错误是意料之中的。

从中复制的类是ArrayListSerializer, ListLikeSerializer, AbstractCollectionSerializerin packagekotlinx.serialization.internal.CollectionSerializer.ktArrayClassDesc, ListLikeDescriptorin 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)

再次,请谨慎使用。从中创建的类仍处于试验阶段,可能随时更改,恕不另行通知。

于 2020-11-16T15:19:05.470 回答