3

I am facing a problem with kotlinx JSON serializing and having a @Serializer annotation on Android. The problem only happens on certain API-levels - seems to work above API level 23 and gives this error below:

java.lang.VerifyError: Rejecting class org.kethereum.wallet.model.KdfSerializer because it failed compile-time verification (declaration of 'org.kethereum.wallet.model.KdfSerializer' appears in /data/app/package.name-1/base.apk:classes3.dex)
        at org.kethereum.wallet.model.WalletCrypto.write$Self(Wallet.kt)
        at org.kethereum.wallet.model.WalletCrypto$$serializer.save(Wallet.kt)
        at org.kethereum.wallet.model.WalletCrypto$$serializer.save(Wallet.kt:15)
        at kotlinx.serialization.KOutput.writeSerializableValue(Serialization.kt:146)
        at kotlinx.serialization.KOutput.writeSerializableElementValue(Serialization.kt:191)
        at org.kethereum.wallet.model.Wallet.write$Self(Wallet.kt)
        at org.kethereum.wallet.model.Wallet$$serializer.save(Wallet.kt)
        at org.kethereum.wallet.model.Wallet$$serializer.save(Wallet.kt:53)
        at kotlinx.serialization.KOutput.write(Serialization.kt:99)
        at kotlinx.serialization.json.JSON.stringify(JSON.kt:40)
        at kotlinx.serialization.json.JSON$Companion.stringify(JSON.kt:57)
        at org.kethereum.wallet.WalletFileKt.generateWalletFile(WalletFile.kt:30)

I found a workaround for my use-case - but would love to understand the problem. When doing this:

@Serializable
data class WalletCrypto(
        var cipher: String,
        var ciphertext: String,
        var cipherparams: CipherParams,
        var kdf: String,
        @Serializable(with = KdfSerializer::class)
        var kdfparams: KdfParams,
        var mac: String) {

        object KdfSerializer : KSerializer<KdfParams> {
            override val serialClassDesc = SerialClassDescImpl("KDFSerializer")

            override fun load(input: KInput) = throw NotImplementedError("loading WalletCrypto is not implemented - use WalletCryptoForImport instead")

            override fun save(output: KOutput, obj: KdfParams) = when (obj) {
                        is ScryptKdfParams -> output.write(obj)
                        is Aes128CtrKdfParams -> output.write(obj)
                }
        }
}

instead of:

@Serializable
data class WalletCrypto(
        var cipher: String,
        var ciphertext: String,
        var cipherparams: CipherParams,
        var kdf: String,
        @Serializable(with = KdfSerializer::class)
        var kdfparams: KdfParams,
        var mac: String) {

        @Serializer(forClass = KdfParams::class)
        object KdfSerializer : KSerializer<KdfParams> {
                override fun save(output: KOutput, obj: KdfParams) = when (obj) {
                        is ScryptKdfParams -> output.write(obj)
                        is Aes128CtrKdfParams -> output.write(obj)
                }
        }
}

the problem is gone. So the problem seems to be rooted in using the @Serializer annotation. KdfParams is a sealed class:

sealed class KdfParams {
    abstract var dklen: Int
    abstract var salt: String?
}
ligi
  • 39,001
  • 44
  • 144
  • 244

0 Answers0