Jackson/Kotlin: No Creators, like default construct, exist — ошибка десериализации
Причина ошибки
Проблема в том, что Jackson по умолчанию требует для десериализации либо пустой конструктор (default constructor), либо конструктор с аннотациями @JsonCreator и @JsonProperty. Kotlin data классы генерируют конструктор с параметрами, но Jackson не знает, как сопоставить параметры JSON с полями конструктора, если явно не указать это.
Вы используете jackson-module-kotlin, но, скорее всего, не подключили его к ObjectMapper. Вот правильное решение.
Шаг 1: Подключите jackson-module-kotlin в build.gradle
dependencies {
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2")
implementation("com.squareup.retrofit2:converter-jackson:2.9.0")
}
Шаг 2: Настройте Retrofit с Jackson конвертером и модулем Kotlin
Создайте кастомный ObjectMapper с зарегистрированным Kotlin модулем и передайте его в Retrofit:
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import retrofit2.Retrofit
import retrofit2.converter.jackson.JacksonConverterFactory
val mapper = jacksonObjectMapper() // Этот метод уже включает Kotlin модуль!
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(JacksonConverterFactory.create(mapper))
.build()
Важно: Используйте jacksonObjectMapper() из jackson-module-kotlin, а не стандартный ObjectMapper(). Первый автоматически регистрирует KotlinModule, который умеет работать с data классами.
Шаг 3: Альтернатива — используйте @JsonCreator (если не хотите менять ObjectMapper)
Если вы не можете настроить ObjectMapper глобально, можно аннотировать конструктор data класса:
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty
data class User @JsonCreator constructor(
@JsonProperty("id") val id: Int,
@JsonProperty("name") val name: String,
@JsonProperty("email") val email: String
)
Но это громоздко, поэтому первый способ предпочтительнее.
Почему это работает?
- KotlinModule анализирует data классы и автоматически определяет, какие параметры конструктора соответствуют полям JSON.
- Он также поддерживает значения по умолчанию (
val name: String = "Unknown"), если поле отсутствует в JSON. - Без этого модуля Jackson видит только пустой конструктор (которого нет) и падает с ошибкой.
Полный пример рабочего кода
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import retrofit2.Retrofit
import retrofit2.converter.jackson.JacksonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
data class User(
val id: Int,
val name: String,
val email: String
)
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Int): User
}
fun main() {
val mapper = jacksonObjectMapper()
val retrofit = Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(JacksonConverterFactory.create(mapper))
.build()
.create(ApiService::class.java)
// Теперь вызов retrofit.getUser(1) будет работать без ошибок
}
Проверьте, что в вашем проекте используется jacksonObjectMapper(), а не ObjectMapper(). Это самая частая причина ошибки.
Альтернативное решение: используйте Gson или Kotlinx Serialization
Если вы не хотите возиться с Jackson, рассмотрите другие библиотеки сериализации, которые лучше интегрированы с Kotlin.
Вариант 1: Gson
Gson по умолчанию работает с Kotlin data классами без дополнительных настроек:
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Retrofit
val retrofit = Retrofit.Builder()
.baseUrl("...")
.addConverterFactory(GsonConverterFactory.create())
.build()
Вариант 2: Kotlinx Serialization (рекомендуется для Kotlin Multiplatform)
Это нативная библиотека Kotlin:
// build.gradle.kts
plugins {
kotlin("plugin.serialization") version "1.9.0"
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
implementation("com.jakewharton.retrofit2:retrofit2-kotlinx-serialization-converter:1.0.0")
}
// Класс
@Serializable
data class User(val id: Int, val name: String, val email: String)
// Retrofit
val retrofit = Retrofit.Builder()
.baseUrl("...")
.addConverterFactory(kotlinx.serialization.json.Json.asConverterFactory("application/json".toMediaType()))
.build()
Оба варианта избавят вас от ошибки "No Creators" и не требуют настройки ObjectMapper. Выбирайте то, что удобнее для вашего проекта.