No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) в Kotlin с Jackson и Retrofit
Причина ошибки
Ошибка возникает из-за того, что Jackson не может создать экземпляр вашего дата-класса UserResponse. В отличие от Java, Kotlin генерирует дата-классы с конструктором, принимающим все поля, но без конструктора без параметров (default constructor). Jackson по умолчанию пытается использовать конструктор без параметров, а затем заполнять поля через сеттеры или рефлексию, но в Kotlin сеттеры не генерируются автоматически для свойств, объявленных в конструкторе.
Решение: подключить jackson-module-kotlin
Вы уже добавили зависимость jackson-module-kotlin, но её нужно зарегистрировать в ObjectMapper, который использует Retrofit. Вот правильная настройка:
// Создаём ObjectMapper с модулем Kotlin
val objectMapper = ObjectMapper().registerModule(KotlinModule.Builder().build())
// Создаём Retrofit с этим ObjectMapper
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.build()
val apiService = retrofit.create(ApiService::class.java)
Модуль KotlinModule добавляет поддержку:
- Конструкторов с параметрами (использует рефлексию для определения порядка аргументов)
- Null-безопасности (учитывает nullable/non-null типы)
- Значений по умолчанию в конструкторе
Альтернативный подход: использовать @JsonCreator
Если по каким-то причинам вы не хотите использовать модуль Kotlin, можно аннотировать конструктор вручную:
data class UserResponse @JsonCreator constructor(
@JsonProperty("id") val id: Int,
@JsonProperty("name") val name: String,
@JsonProperty("email") val email: String
)
Но это громоздко и неудобно для проектов с большим количеством моделей.
Проверка зависимостей
Убедитесь, что у вас нет конфликта версий. Рекомендуемые версии (для Jackson 2.15.x):
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2")
implementation("com.squareup.retrofit2:converter-jackson:2.9.0")
Если ошибка остаётся
Попробуйте добавить конструктор без параметров в дата-класс со значениями по умолчанию:
data class UserResponse(
val id: Int = 0,
val name: String = "",
val email: String = ""
)
Но это плохая практика — лучше решить проблему через модуль Kotlin.
Полный пример рабочего кода
// Модель
data class UserResponse(
val id: Int,
val name: String,
val email: String
)
// Retrofit клиент
val objectMapper = ObjectMapper().registerModule(KotlinModule.Builder().build())
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(JacksonConverterFactory.create(objectMapper))
.build()
val apiService = retrofit.create(ApiService::class.java)
// Использование
lifecycleScope.launch {
try {
val user = apiService.getUser(1)
println(user.name) // Работает!
} catch (e: Exception) {
Log.e("TAG", "Ошибка: ${e.message}")
}
}
После регистрации модуля Kotlin Jackson сможет корректно десериализовать JSON в дата-классы Kotlin без дополнительных аннотаций.
<<Альтернативное решение: использовать kotlinx.serialization вместо Jackson
Если вы не привязаны жёстко к Jackson, рекомендую рассмотреть kotlinx.serialization — это официальная библиотека сериализации от JetBrains, которая лучше интегрируется с Kotlin и не требует дополнительных модулей.
Для этого:
- Добавьте плагин в
build.gradle.kts(проект):id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0" - Добавьте зависимости:
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") - Аннотируйте дата-класс:
@Serializable data class UserResponse(...) - Используйте конвертер Retrofit:
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0")
Пример настройки:
@Serializable
data class UserResponse(
val id: Int,
val name: String,
val email: String
)
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
.build()
Преимущества: не нужно регистрировать модули, работает из коробки с дата-классами, поддерживает sealed-классы и полиморфизм. Недостаток — меньше гибкости, чем у Jackson, для сложных случаев (например, кастомные десериализаторы).
Ответов пока нет.
Войдите чтобы оставить ответ