Как мне выполнить десериализацию списка объектов с помощью библиотеки сериализации Kotlin?

#android #json #kotlin #algolia #instantsearch

#Android #json #kotlin #algolia #мгновенный поиск

Вопрос:

Во время выполнения я столкнулся со следующим исключением, когда отладчик пытался десериализовать данные из моего индекса Algolia для моего приложения Kotlin Android recipe, которое я пытаюсь создать с помощью библиотеки Kotlinx.Serialization. Приложение компилируется и работает нормально, но в пользовательском интерфейсе результаты не отображаются.

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

У меня есть классы данных для рецепта, настроенные следующим образом:

Recipe.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
    ) {
  

Ingredient.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 правильно, а также все создание списка ингредиентов отвлекло меня. Любая помощь была бы очень признательна, и я прошу прощения за то, что мой первый пост здесь был длинным. Я занимаюсь этим уже пару дней, и я в тупике относительно того, что делать дальше.

Ответ №1:

Как вы можете видеть эту строку:

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

Здесь возникает исключение JsonDecodingException, поэтому он не дает правильного ответа. Вы должны проверить, что все ваши классы данных являются той же переменной, которая находится в объекте JSON.

Здесь я обнаружил 1 проблему в вашем классе данных, сначала проверьте этот репозиторий JSON:

 "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 all переменной в классе данных, чтобы проверить правильность отображения всех ответов, а затем просто преобразуйте их в Int, Float в соответствии с вашими требованиями.

Комментарии:

1. Спасибо, что так оно и было! Не могу поверить, что я это пропустил.