需要在 Kotlin 中将 Any 序列化为 base64 字符串

Need to serialize Any to base64 string in Kotlin

我在 Kotlin 中有以下代码,我打算用它来将任何实例转换为 base64 编码的字符串。同样不起作用,它会引发以下错误:

Serializer for class 'Any' is not found.\nMark the class as @Serializable or provide the serializer explicitly

我该如何解决这个问题?

class SerializerAdapter: SerializerPort {
  private val logger: Logger = LoggerFactory.getLogger(javaClass.simpleName)
  override fun toBase64(input: Any): String {
    try {
      val jsonString = Json.encodeToString(input)
      return Base64.getEncoder().encodeToString(jsonString.toByteArray())
    }catch (ex: Exception) {
      logger.error("[BASE64 Error] error converting json object to base64 encoded string: ${ex.stackTraceToString()}")
    }finally {
      return ""
    }
  }
}

仅序列化 Any 并不像听起来那么简单。序列化框架必须知道要序列化的数据类型。它可以使用编译类型(在您的情况下为 Any)或运行时类型(提供给 toBase64() 的实际类型)。这两种选择都有其缺点。由于类型擦除,运行时类型不完整,例如List<Int>List<String> 是一样的。另一方面,编译时类型可能会完全丢失,例如在泛型或像你这样的情况下。

Kotlin 序列化通常更喜欢编译类型,尤其是因为 reified 参数使它们更有用。遗憾的是,我们这里不能使用reified,因为toBase64()是一个虚函数,所以不能内联。

我的建议是更改此函数的签名以额外接收 KType 提供的数据,然后创建内联函数以方便使用:

override fun toBase64(input: Any, type: KType): String {
    try {
        val serializer = Json.serializersModule.serializer(type)
        val jsonString = Json.encodeToString(serializer, input)
        ...
    }
}

@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T>  SerializerPort.toBase64(input: Any) = toBase64(input, typeOf<T>())

或者,我们可以使用运行时类型进行序列化,但请注意我之前提到的问题 - 它可能不适用于泛型。

val serializer = Json.serializersModule.serializer(input::class.starProjectedType)
val jsonString = Json.encodeToString(serializer, input)

kotlinx.serialization 是一个 编译时 库,因此您必须预先知道要序列化的每个对象。

取决于您的用例;

  • 您可能需要使用使用反射的 runtime 库(例如许多 JSON 或 XML 序列化程序之一)能够使用不属于您自己的 类。
  • 或者,如果您的要求更多是希望能够序列化其他人 类,那么您可以使用自己的接口,其他人必须与 @Serializable 一起实现(参见 https://github.com/Kotlin/kotlinx.serialization/issues/1005)。