
commonMain.io.ktor.util.converters.ConversionService.kt Maven / Gradle / Ivy
/*
* Copyright 2014-2021 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/
package io.ktor.util.converters
import io.ktor.util.reflect.*
import kotlin.reflect.*
/**
* Data conversion service that does serialization and deserialization to/from list of strings
*/
public interface ConversionService {
/**
* Deserialize [values] to an instance of [type]
*/
public fun fromValues(values: List, type: TypeInfo): Any?
/**
* Serialize a [value] to values list
*/
public fun toValues(value: Any?): List
}
/**
* The default conversion service that supports only basic types and enums
*/
public object DefaultConversionService : ConversionService {
override fun toValues(value: Any?): List {
if (value == null) {
return emptyList()
}
val converted = platformDefaultToValues(value)
if (converted != null) {
return converted
}
return when (value) {
is Iterable<*> -> value.flatMap { toValues(it) }
else -> {
when (val klass = value::class) {
Int::class,
Float::class,
Double::class,
Long::class,
Short::class,
Char::class,
Boolean::class,
String::class -> listOf(value.toString())
else -> throw DataConversionException(
"Class $klass is not supported in default data conversion service"
)
}
}
}
}
override fun fromValues(values: List, type: TypeInfo): Any? {
if (values.isEmpty()) {
return null
}
if (type.type == List::class || type.type == MutableList::class) {
val argumentType = type.kotlinType?.arguments?.single()?.type?.classifier as? KClass<*>
if (argumentType != null) {
return values.map { fromValue(it, argumentType) }
}
}
when {
values.isEmpty() ->
throw DataConversionException("There are no values when trying to construct single value $type")
values.size > 1 ->
throw DataConversionException("There are multiple values when trying to construct single value $type")
else -> return fromValue(values.single(), type.type)
}
}
public fun fromValue(value: String, klass: KClass<*>): Any {
val converted = convertPrimitives(klass, value)
if (converted != null) {
return converted
}
val platformConverted = platformDefaultFromValues(value, klass)
if (platformConverted != null) {
return platformConverted
}
throwConversionException(klass.toString())
}
private fun convertPrimitives(klass: KClass<*>, value: String) = when (klass) {
Int::class -> value.toInt()
Float::class -> value.toFloat()
Double::class -> value.toDouble()
Long::class -> value.toLong()
Short::class -> value.toShort()
Char::class -> value.single()
Boolean::class -> value.toBoolean()
String::class -> value
else -> null
}
private fun throwConversionException(typeName: String): Nothing {
throw DataConversionException("Type $typeName is not supported in default data conversion service")
}
}
internal expect fun platformDefaultFromValues(value: String, klass: KClass<*>): Any?
internal expect fun platformDefaultToValues(value: Any): List?
/**
* Thrown when failed to convert value
*/
public open class DataConversionException(message: String = "Invalid data format") : Exception(message)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy