Ktor с сериализацией kotlinx: как использовать JSON.nonstrict

Я пытаюсь инициализировать клиент Ktor http и настроить сериализацию JSON. Мне нужно разрешить нестрогую десериализацию, которую позволяет объект JSON.nonstrict. Просто не могу понять, как применить этот параметр к сериализатору.

 val client = HttpClient {
                install(JsonFeature) {
                    serializer = KotlinxSerializer()                    
                }
        }

11 ответов

Вы можете указать конфигурации json с помощью построителя Json, который вы передаете в KotlinxSerializer.

val client = HttpClient {
    install(JsonFeature) {
        serializer = KotlinxSerializer(Json {
            isLenient = true
            ignoreUnknownKeys = true
        })                    
    }
}

Точные поля для построителя Json являются экспериментальными и могут быть изменены, поэтому ознакомьтесь с исходным кодом здесь.

После выхода Kotlin 1.4.0:

val response = Json {
            ignoreUnknownKeys = true
        }
            .decodeFromString(ResponseObject.serializer(), jsonString)

А вы httpClient:

            HttpClient {
                install(JsonFeature) {
                    serializer = KotlinxSerializer()
                }
                install(Logging) {
                    logger = Logger.DEFAULT
                    level = LogLevel.ALL
                }
            }

Разобрался - можем перейти в конструктор:

serializer = KotlinxSerializer(JSON.nonstrict)

Это очень часто меняется, но с Kotlin 1.4.10 и Ktor 1.4.1 вам нужно передать kotlinx Json (будьте осторожны, потому что также есть io.ktor.client.features.json.Json, Я использовал псевдоним импорта, чтобы различать их, потому что мне нужны были оба import kotlinx.serialization.json.Json as KotlinJson)

val client = HttpClient {
    install(JsonFeature) {
        serializer = KotlinxSerializer(KotlinJson { ignoreUnknownKeys = true })
    }
    ...

Для тех, кто использует дооснащение, вы можете рассмотреть возможность использования JsonConfiguration(strictMode = false) на застройщиках.

Например:

// your retrofit builder
Retrofit.Builder()
        .baseUrl(url)
        .client(okHttpClient)
        .client(httpClient)
        .addConverterFactory(
          Json(JsonConfiguration(strictMode = false))
              .asConverterFactory(MediaType.get("application/json")
        )
)

Источник: выпуск на github kotlinx

В версии "1.0.0RC" использование дооснащения выглядит следующим образом.

Retrofit.Builder()
        .client(okHttpClient)
        .baseUrl(Env.BASE_URL)
        .addConverterFactory(Json{
            isLenient = true
            ignoreUnknownKeys = true
        }.asConverterFactory(MediaType.get("application/json")))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .build()

Для ктор 2.0+

              return HttpClient(CIO) {
            engine {
                maxConnectionsCount = 10
            }

            install(ContentNegotiation) {
                json(kotlinx.serialization.json.Json {
                    ignoreUnknownKeys = true
                })
            }

            install(HttpTimeout) {
                requestTimeoutMillis = 1000L
                connectTimeoutMillis = 1000L
                socketTimeoutMillis = 1000L
            }
        }

Исходя из ответа Родиона Альтшулера выше, это то, что сработало для меня в моем проекте KMP:

install(JsonFeature) {
    serializer = KotlinxSerializer(kotlinx.serialization.json.Json(JsonConfiguration.Stable.copy(strictMode = false))).apply {
      useDefaultTransformers = true
    }
}

Вроде для 1.4.32 у меня так:

      install(JsonFeature) {
                    serializer = KotlinxSerializer(json = kotlinx.serialization.json.Json {
                        isLenient = true
                        ignoreUnknownKeys = true
                    })
                }

Вот как вы можете настроить JsonConfig для реактивного веб-клиента Spring:

      

val json = Json { ignoreUnknownKeys = true isLenient = true }

val strategies = ExchangeStrategies
    .builder()
    .codecs { clientDefaultCodecsConfigurer ->
        run {
            clientDefaultCodecsConfigurer.defaultCodecs()
                .kotlinSerializationJsonDecoder(KotlinSerializationJsonDecoder(json))
            clientDefaultCodecsConfigurer.defaultCodecs()
                .kotlinSerializationJsonEncoder(KotlinSerializationJsonEncoder(json))

        }
    }.build()

return WebClient
    .builder()
    .exchangeStrategies(strategies)
    .baseUrl(baseUrl!!)
    .build()

Модернизация принимает только клиентов типа okhttp

Невозможно передать, например, org.springframework.web.reactive.function.client.Webclient?

Насколько я знаю

      val response = Json {
            ignoreUnknownKeys = true
        }
            .decodeFromString(ResponseObject.serializer(), jsonString)

Это должно управляться для соответствующего класса @Serialiazble, верно?

Нет ли другого варианта в Kotlin + Spring Webflux для решения этой проблемы вместо использования, например, сопоставления объектов Jackson или необходимости реализации этого для соответствующего объекта @Serializable для игнорирования неизвестных ключей при использовании Spring Webclient?

Другие вопросы по тегам