Data Conversion

预计阅读时间:3分钟

DataConversion是一项允许序列化和反序列化值列表的功能.

默认情况下,它处理原始类型和枚举,但也可以配置为处理其他类型.

如果您正在使用" 位置信息"功能,并且希望支持自定义类型作为其参数的一部分,则可以使用此服务添加新的自定义转换器.

目录:

此功能在io.ktor.features.DataConversion类中io.ktor.features.DataConversion ,不需要其他工件.

Basic Installation

安装DataConversion非常容易,它应该涵盖原始类型:

install(DataConversion)

Adding Converters

DataConversion配置提供了convert<T>方法来定义类型转换. 在内部,您必须提供一个解码器和一个编码器,以及带有接受回调的decodeencode方法.

  • 解码回调: converter: (values: List<String>, type: Type) -> Any? 接受values ,字符串的列表)表示的URL的重复值,例如, a=1&a=2 ,并且接受该type转换到. 它应该返回解码后的值.
  • 编码回调: converter: (value: Any?) -> List<String>接受任意值,并应返回表示该值的字符串列表. 返回单个元素的列表时,它将被序列化为key=item1 . 对于多个值,它将在查询字符串中序列化为: samekey=item1&samekey=item2 .

例如:

install(DataConversion) {
    convert<Date> { // this: DelegatingConversionService
        val format = SimpleDateFormat.getInstance()
    
        decode { values, _ -> // converter: (values: List<String>, type: Type) -> Any?
            values.singleOrNull()?.let { format.parse(it) }
        }

        encode { value -> // converter: (value: Any?) -> List<String>
            when (value) {
                null -> listOf()
                is Date -> listOf(SimpleDateFormat.getInstance().format(value))
                else -> throw DataConversionException("Cannot convert $value as Date")
            }
        }
    }
}

另一个潜在的用途是自定义特定枚举的序列化方式. 默认情况下,枚举使用大小写敏感的.name序列化和反序列化. 但是,例如,您可以将它们序列化为小写并以不区分大小写的方式反序列化它们:

enum class LocationEnum {
    A, B, C
}

@Location("/") class LocationWithEnum(val e: LocationEnum)

@Test fun `location class with custom enum value`() = withLocationsApplication {
    application.install(DataConversion) {
        convert(LocationEnum::class) {
            encode { if (it == null) emptyList() else listOf((it as LocationEnum).name.toLowerCase()) }
            decode { values, type -> LocationEnum.values().first { it.name.toLowerCase() in values } }
        }
    }
    application.routing {
        get<LocationWithEnum> {
            call.respondText(call.locations.resolve<LocationWithEnum>(LocationWithEnum::class, call).e.name)
        }
    }

    urlShouldBeHandled("/?e=a", "A")
    urlShouldBeHandled("/?e=b", "B")
}

Accessing the Service

您可以通过以下任何方式轻松调用DataConversion服务:

val dataConversion = call.conversionService

The ConversionService Interface

interface ConversionService {
    fun fromValues(values: List<String>, type: Type): Any?
    fun toValues(value: Any?): List<String>
}
class DelegatingConversionService(private val klass: KClass<*>) : ConversionService {
    fun decode(converter: (values: List<String>, type: Type) -> Any?)
    fun encode(converter: (value: Any?) -> List<String>)
}

by  ICOPY.SITE