【问题标题】:How would I go about de-serializing a list of objects using Kotlin's serialization library?我将如何使用 Kotlin 的序列化库反序列化对象列表?
【发布时间】:2020-09-24 04:04:14
【问题描述】:

我在运行时遇到了以下异常,调试器尝试从我的 Algolia 索引中反序列化我尝试使用 Kotlinx.Serialization 库创建的 Kotlin Android 食谱应用程序的数据。应用程序编译并运行良好,但 UI 上没有显示结果。

kotlinx.serialization.json.JsonDecodingException: Unexpected JSON token at offset -1: Failed to parse 'int'.
 JSON input: {"amount":1.5,"name":"green beans","original":"1.5 pounds of green beans","unit":"pounds","unitLong":"pounds","unitShort":"lbs"}

现在从这个异常的外观来看,反序列化器似乎很困惑尝试反序列化我的 Ingredients 数据类。我将如何去反序列化它?。

正在发送的示例 JSON 数据。

{
  "cuisine": "European",
  "diet": "Vegetarian",
  "difficulty": 2,
  "dishType": "Dinner",
  "duration": 30,
  "durationUnit": "minutes",
  "image": "https://c.recipeland.com/images/r/1396/12f9fc271d8f1bfac5f6_550.jpg",
  "ingredients": [
    {
      "amount": 1.5,
      "name": "green beans",
      "original": "1.5 pounds of green beans",
      "unit": "pounds",
      "unitLong": "pounds",
      "unitShort": "lbs"
    },
    {
      "amount": 1,
      "name": "onion",
      "original": "1.5 medium onion",
      "unit": "medium",
      "unitLong": "medium",
      "unitShort": "med"
    },
    {
      "amount": 2,
      "name": "garlic",
      "original": "2 teaspoons of garlic",
      "unit": "teaspoons",
      "unitLong": "teaspoons",
      "unitShort": "tsps"
    },
    {
      "amount": 1,
      "name": "olive oil",
      "original": "1 teaspoon olive oil",
      "unit": "teaspoon",
      "unitLong": "teaspoon",
      "unitShort": "tsps"
    },
    {
      "amount": 1,
      "name": "mushrooms",
      "original": "1 cup mushrooms",
      "unit": "cup",
      "unitLong": "cup",
      "unitShort": "cup"
    },
    {
      "amount": 1,
      "name": "cherry tomatoes",
      "original": "1 cup cherry tomatoes",
      "unit": "cup",
      "unitLong": "cup",
      "unitShort": "cup"
    }
  ],
  "name": "Green Beans with Mushrooms and Cherry Tomatoes",
  "preparation": [
    "Steam green beans until tender.",
    "Drain and set aside. Sauté onion and garlic in a medium skillet coated with olive oil, until tender. About 2 to 3 minutes.",
    "Add mushrooms and sauté until tender. Stir in green beans and tomotoes until heated."
  ],
  "yield": 4,
  "objectID": "0"
}

我的食谱数据类设置如下:

食谱.kt

@IgnoreExtraProperties
@Serializable
data class Recipe(
    var difficulty: Int = 0,
    var dishType: String? = null,
    var duration: Int = 0,
    var durationUnit: String? = null,
    var image: String? = null,
    var diet: String? = null,
    var cuisine: String? = null,
    var name: String? = null,
    var ingredients: List<Ingredient> = emptyList(),
    var preparation: List<String> = emptyList(),
    var yield: Int = 0
    ) {

成分.kt

@Serializable
data class Ingredient(
    var amount: Int = 0,
    var name: String? = null,
    var original: String? = null, // Original text of the ingredient
    var unit: String? = null,
    var unitLong: String? = null,
    var unitShort: String? = null
)

我从 Algolia 的 InstantSearch Android 入门指南中获得的这段代码,用于对索引中的数据进行反序列化。

    private val datasourceFactory = SearcherSingleIndexDataSource.Factory(searcher) { hit ->
        hit.deserialize(Recipe.serializer()) // Problem line I assume
    }

    val pagedListConfig = PagedList.Config.Builder().setPageSize(50).build()
    val recipes: LiveData<PagedList<Recipe>> =
        LivePagedListBuilder(datasourceFactory, pagedListConfig).build()
    val searchBox =
        SearchBoxConnectorPagedList(searcher, listOf(recipes))

我尝试使用以下代码手动创建对象,但在尝试创建成分列表时遇到问题。

    val dataSourceFactory = SearcherSingleIndexDataSource.Factory(searcher) { hit ->
        Recipe(
            hit.json.getPrimitive("difficulty").content.toInt(),
            hit.json.getPrimitive("dishType").content,
            hit.json.getPrimitive("duration").content.toInt(),
            hit.json.getPrimitive("durationUnit").content,
            hit.json.getPrimitive("image").content,
            hit.json.getPrimitive("diet").content,
            hit.json.getPrimitive("cuisine").content,
            hit.json.getPrimitive("name").content,
            listOf(
                Ingredient(
                    hit.json.getPrimitive("amount").content.toInt(),
                    hit.json.getPrimitive("name").content,
                    hit.json.getPrimitive("original").content,
                    hit.json.getPrimitive("unit").content,
                    hit.json.getPrimitive("unitLong").content,
                    hit.json.getPrimitive("unitShort").content
                )
            ),
            hit.json.getArray("preparation").content.map { prep -> prep.content },
            hit.json.getPrimitive("yield").content.toInt()
        )
    }

我不能 100% 确定我是否正确地创建了 preparation 属性成员,以及整个创建成分列表的过程都让我偏离了方向。任何帮助将不胜感激,对于我在这里的第一篇文章很长,我深表歉意。我已经为此做了几天了,我不知道下一步该做什么。

【问题讨论】:

    标签: android json kotlin algolia instantsearch


    【解决方案1】:

    如你所见:

    kotlinx.serialization.json.JsonDecodingException: Unexpected JSON token at offset -1: Failed to parse 'int'.
    

    这里发生 JsonDecodingException 异常,这就是它没有给出正确响应的原因。您必须检查所有数据类是否与 JSON 对象中的相同变量。

    我在你的数据类中发现了 1 个问题,首先检查这个 JSON Reposne:

    "amount": 1.5
    

    现在检查你的数据类,它有var amount: Int = 0

    @Serializable
    data class Ingredient(
        var amount: Int = 0,
        var name: String? = null,
        var original: String? = null, // Original text of the ingredient
        var unit: String? = null,
        var unitLong: String? = null,
        var unitShort: String? = null
    )
    

    这里的 JSON 对象在 Float 中,而您将其存储在 Int 中,这可能会导致异常。确保数据类中的所有值都是正确的。

    或者为了解决您的问题,只需在数据类中创建 String 所有变量以检查所有响应显示是否正确,而不是根据您的要求将它们转换为 Int、Float。

    【讨论】:

    • 谢谢你,原来是这样!不敢相信我错过了。
    猜你喜欢
    • 1970-01-01
    • 2014-12-10
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 2018-08-17
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    相关资源
    最近更新 更多