我正在将gson迁移到moshi,但我在序列化列表时遇到了问题.我对"普通"对象没有问题,但对列表有问题.

我有一个类ImageDTO(包括一个Moshi适配器),如下所示:

class ImageDTO (
    val idImage: String = "",
    val idQuestion: String = "",
    val image: String = "",
    val timestamp: Int = 0,
    var saveMode: String = ""
) {
    @JsonClass(generateAdapter = true)
    class ImageDTOIntermediate(
        @Json(name = "idImage")
        val idImage: String,
        @Json(name = "idQuestion")
        val idQuestion: String,
        @Json(name = "image")
        val image: String,
        @Json(name = "timestamp")
        val timestamp: Int,
        @Json(name = "saveMode")
        var saveMode: String = ""
    )

    companion object {
        val JSON_ADAPTER: Any = object : Any() {
            @ToJson
            private fun toJson(imageDTO: ImageDTO): String {

                val idImage = imageDTO.idImage
                val idQuestion = imageDTO.idQuestion
                val image = imageDTO.image
                val timestamp = imageDTO.timestamp
                val saveMode = imageDTO.saveMode

                val imageDTOIntermediate = ImageDTOIntermediate(idImage, idQuestion, image, timestamp, saveMode)

                return imageDTOIntermediate.serialize()
            }

            @FromJson
            private fun fromJson(imageDTOIntermediate: ImageDTOIntermediate): ImageDTO {

                val idImage = imageDTOIntermediate.idImage
                val idQuestion = imageDTOIntermediate.idQuestion
                val image = imageDTOIntermediate.image
                val timestamp = imageDTOIntermediate.timestamp
                val saveMode = imageDTOIntermediate.saveMode

                return ImageDTO(idImage, idQuestion, image, timestamp, saveMode)
            }
        }
    }
}

在序列化时,我希望接下来会有一个这样的Json:

[
   {
      "idImage":"f3d4befc-4569-c0c5-19b1-2865fcab5d33",
      "idQuestion":"65d5254b-cb6d-a099-9f6d-71d93dcdcadb",
      "image":"65d5254b-cb6d-a099-9f6d-71d93dcdcadb_q5_1.png",
      "saveMode":"",
      "timestamp":1498856479
   },
   {
      "idImage":"66eb6535-f4b2-a130-6e90-cf53ce95bb63",
      "idQuestion":"d23f87c0-cbc5-84b8-34cd-f5be4faced21",
      "image":"d23f87c0-cbc5-84b8-34cd-f5be4faced21_i4_1.png",
      "saveMode":"",
      "timestamp":1538922258
   },
   {
      "idImage":"016bba85-a023-8fb0-5aa4-71a0665dab94",
      "idQuestion":"ad8e3eec-bd5a-aefa-fedf-28d51d82ab49",
      "image":"ad8e3eec-bd5a-aefa-fedf-28d51d82ab49_i5_1.png",
      "saveMode":"",
      "timestamp":1626640944
   }
]

以这种方式使用gson:

private var images: List<ImageDTO>
...
Gson().toJson(images)

我成功地获得了预期的Json,但是使用上面给出的适配器使用Moshi,我得到了一个表面上正确的Json字符串,但带有转义的双引号(\"),这对我来说是有意义的,因为适配器中的Serialize in ToJson方法.每个单独的ImageDTO对象都被正确地序列化,但是在构建列表时,最终的字符串已经对所有内部双引号进行了转义,我不知道如何处理这个问题.

下面是我的Moshi/Json扩展类:

object TMJson {

    val moshi: Moshi = Moshi.Builder()
        .add(User.JSON_ADAPTER)
        .add(ImageDTO.JSON_ADAPTER)
        .build()

    inline fun <reified T> T.serialize(): String {
        val adapter: JsonAdapter<T> = moshi.adapter(T::class.java)
        return adapter.toJson(this)
    }

    inline fun <reified T> String.deserialize(): T? {
        val adapter: JsonAdapter<T> = moshi.adapter(T::class.java)
        return adapter.fromJson(this)
    }

    inline fun <reified T> String.serialize(): MutableList<T>? {
        return moshi.serialize(this)
    }

    inline fun <reified T> Moshi.serialize(jsonString: String): MutableList<T>? {
        return adapter<MutableList<T>>(Types.newParameterizedType(List::class.java, T::class.java)).fromJson(jsonString)
    }
}

我想我的Moshi适配器可以简化,但不确定具体如何简化,这不是我的主要问题,而是像这样序列化的列表(为了简单起见,我不在这里放值:

["{\"idImage\":\"\",\"idQuestion\":\"\",\"image\":\"\",\"timestamp\":0,\"saveMode\":\"\"}","{\"idImage\":\"\",\"idQuestion\":\"\",\"image\":\"\",\"timestamp\":0,\"saveMode\":\"\"}","{\"idImage\":\"\",\"idQuestion\":\"\",\"image\":\"\",\"timestamp\":0,\"saveMode\":\"\"}","{\"idImage\":\"\",\"idQuestion\":\"\",...]

我不想使用KotlinJsonAdapterFactory(),而是使用定制适配器,因为它速度更快.

在我的build.gradle中:

implementation('com.squareup.moshi:moshi-kotlin:1.15.0')
ksp("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")

对我的列表进行正确的序列化有什么帮助吗?

编辑1:这是我调用json/moshi扩展的方式.

private var images: List<ImageDTO>?
...
override fun call(): String {
    images = getImagesFromTests(testsDTO)
    val images1 = Gson().toJson(images) //=> Works
    val images2 = images!!.serialize1() //=> Does not work
    val tests = updateLocalDatabaseTests(testsDTO)
    return "{\"tests\": [$tests], \"images\": [$images1]}"
}

我必须补充的是,"Call"方法是一个后台任务,当调用"Call"方法时,图像(ImageDTO列表)已经有了值.

编辑2:关于项目的额外信息.

我不认为这是相关的,但以防万一,我会补充说,我的应用程序是一个多模块的应用程序.类"ImageDTO"位于MyApp.DTO模块中,而TMJson扩展位于MyApp.Common模块中.

由于循环依赖,我不能在"DTO"中引用"Common",所以我最后用Serialize方法克隆了"TMJson"扩展类.

让我困惑的是,在根本没有数据修改的情况下,需要使用中间对象来进行序列化,但这是我在网上找到的一个例子,这是我知道的唯一做到这一点的方法.

推荐答案

问题出在适配器对象的@ToJson中.目前,您的@ToJson返回的是字符串类型.Moshi将该字符串视为仍然需要编码为JSON的字符串,但实际上返回的是编码的JSON字符串.这导致了双重编码.

你需要做的就是退还你的ImageDTOIntermediate美元,与你的@FromJson美元一模一样.让莫西给你拿ImageDTOIntermediate号的适配器.

@ToJson
private fun toJson(imageDTO: ImageDTO): ImageDTOIntermediate {
  val idImage = imageDTO.idImage
  val idQuestion = imageDTO.idQuestion
  val image = imageDTO.image
  val timestamp = imageDTO.timestamp
  val saveMode = imageDTO.saveMode
  return ImageDTOIntermediate(idImage, idQuestion, image, timestamp, saveMode)
}

Json相关问答推荐

如何将加权边列表导出到JSON树?

处理输入数据并转换为更简单的格式-PowerBI

在Reaction中从JSON文件中筛选数组

解析SQL中的嵌套JSON

使用Kotlin限制序列化类属性的允许整数值

nlohmann json:为什么我会得到一个解析错误?

Spark-SQL中的from_unixtime函数未能给出正确的输出

我无法将来自 API 的数据显示到 FlatList 中,但我在 console.log 中看到了它.问题是什么?

Kotlin Android Room 处理 Moshi TypeConverter 中的空对象列表

Flutter:在本地文件 json 中搜索特殊的阿拉伯字符

使用 jq 同时迭代数组

Play Framework:如何序列化/反序列化与 JSON 的枚举

如何一次加载无限滚动中的所有条目以解析python中的HTML

json.decoder.JSONDecodeError:期望值:第 1 行第 1 列(字符 0)

Java JSON 序列化 - 最佳实践

在 JSON.stringify() 的输出中隐藏空值

Golang struct 的 XML 和 JSON 标签?

Spring restTemplate 获取原始 json 字符串

如何将 MongoDB 查询转换为 JSON?

通过 JSON 发送 64 位值的公认方式是什么?