没有 @Serializable 的数据 class 的自定义序列化程序
Custom serializer for data class without @Serializable
我正在尝试将 JSON 文件反序列化为 Kotlin 数据 class 我无法使用 kotlinx.serialization
.
进行控制
class 看起来类似于:
public data class Lesson(
val uid: String,
val start: Instant,
val end: Instant,
val module: String,
val lecturers: List<String>,
val room: String?,
val type: String?,
val note: String?
)
我尝试解析的 JSON 看起来像这样:
{
"lessons": [
{
"uid": "sked.de956040",
"start": "2020-11-02T13:30:00Z",
"end": "2020-11-02T16:45:00Z",
"module": "IT2101-Labor SWE I: Gruppe 1 + 2",
"lecturers": [
"Kretzmer"
],
"room": "-",
"type": "La",
"note": "Prüfung Online"
}
]
}
这是通过以下方式尝试的:
@Serializable
data class ExpectedLessons(
val lessons: List<Lesson>
)
val decoded = Json.decodeFromString<ExpectedLessons>(text)
由于无法修改 class Lesson
,因此无法添加 @Serializable
注释来进行(反)序列化。
因此,您可以创建两个自定义序列化器来使其工作。
@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = Lesson::class)
object LessonSerializer : KSerializer<Lesson> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Lesson") {
element<String>("uid")
element<String>("start")
element<String>("end")
element<String>("module")
element<List<String>>("lecturers")
element<String?>("room", isOptional = true)
element<String?>("type", isOptional = true)
element<String?>("note", isOptional = true)
}
override fun serialize(encoder: Encoder, value: Lesson) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.uid)
encodeSerializableElement(descriptor, 1, InstantSerializer, value.start)
encodeSerializableElement(descriptor, 2, InstantSerializer, value.end)
encodeStringElement(descriptor, 3, value.module)
encodeSerializableElement(descriptor, 4, ListSerializer(String.serializer()), value.lecturers)
encodeNullableSerializableElement(descriptor, 5, String.serializer(), value.room)
encodeNullableSerializableElement(descriptor, 6, String.serializer(), value.type)
encodeNullableSerializableElement(descriptor, 7, String.serializer(), value.note)
}
}
override fun deserialize(decoder: Decoder): Lesson {
return decoder.decodeStructure(descriptor) {
var uid: String? = null
var start: Instant? = null
var end: Instant? = null
var module: String? = null
var lecturers: List<String> = emptyList()
var room: String? = null
var type: String? = null
var note: String? = null
loop@ while (true) {
when (val index = decodeElementIndex(descriptor)) {
DECODE_DONE -> break@loop
0 -> uid = decodeStringElement(descriptor, 0)
1 -> start = decodeSerializableElement(descriptor, 1, InstantSerializer)
2 -> end = decodeSerializableElement(descriptor, 2, InstantSerializer)
3 -> module = decodeStringElement(descriptor, 3)
4 -> lecturers = decodeSerializableElement(descriptor, 4, ListSerializer(String.serializer()))
5 -> room = decodeNullableSerializableElement(descriptor, 5, String.serializer().nullable)
6 -> type = decodeNullableSerializableElement(descriptor, 6, String.serializer().nullable)
7 -> note = decodeNullableSerializableElement(descriptor, 7, String.serializer().nullable)
else -> throw SerializationException("Unexpected index $index")
}
}
Lesson(
requireNotNull(uid),
requireNotNull(start),
requireNotNull(end),
requireNotNull(module),
lecturers,
room,
type,
note
)
}
}
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = Instant::class)
object InstantSerializer : KSerializer<Instant> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Instant) {
encoder.encodeString("$value")
}
override fun deserialize(decoder: Decoder): Instant {
return Instant.parse(decoder.decodeString())
}
}
您可以像这样在使用序列化程序之前配置它们:
@file:UseSerializers(InstantSerializer::class, LessonSerializer::class)
我正在尝试将 JSON 文件反序列化为 Kotlin 数据 class 我无法使用 kotlinx.serialization
.
class 看起来类似于:
public data class Lesson(
val uid: String,
val start: Instant,
val end: Instant,
val module: String,
val lecturers: List<String>,
val room: String?,
val type: String?,
val note: String?
)
我尝试解析的 JSON 看起来像这样:
{
"lessons": [
{
"uid": "sked.de956040",
"start": "2020-11-02T13:30:00Z",
"end": "2020-11-02T16:45:00Z",
"module": "IT2101-Labor SWE I: Gruppe 1 + 2",
"lecturers": [
"Kretzmer"
],
"room": "-",
"type": "La",
"note": "Prüfung Online"
}
]
}
这是通过以下方式尝试的:
@Serializable
data class ExpectedLessons(
val lessons: List<Lesson>
)
val decoded = Json.decodeFromString<ExpectedLessons>(text)
由于无法修改 class Lesson
,因此无法添加 @Serializable
注释来进行(反)序列化。
因此,您可以创建两个自定义序列化器来使其工作。
@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = Lesson::class)
object LessonSerializer : KSerializer<Lesson> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Lesson") {
element<String>("uid")
element<String>("start")
element<String>("end")
element<String>("module")
element<List<String>>("lecturers")
element<String?>("room", isOptional = true)
element<String?>("type", isOptional = true)
element<String?>("note", isOptional = true)
}
override fun serialize(encoder: Encoder, value: Lesson) {
encoder.encodeStructure(descriptor) {
encodeStringElement(descriptor, 0, value.uid)
encodeSerializableElement(descriptor, 1, InstantSerializer, value.start)
encodeSerializableElement(descriptor, 2, InstantSerializer, value.end)
encodeStringElement(descriptor, 3, value.module)
encodeSerializableElement(descriptor, 4, ListSerializer(String.serializer()), value.lecturers)
encodeNullableSerializableElement(descriptor, 5, String.serializer(), value.room)
encodeNullableSerializableElement(descriptor, 6, String.serializer(), value.type)
encodeNullableSerializableElement(descriptor, 7, String.serializer(), value.note)
}
}
override fun deserialize(decoder: Decoder): Lesson {
return decoder.decodeStructure(descriptor) {
var uid: String? = null
var start: Instant? = null
var end: Instant? = null
var module: String? = null
var lecturers: List<String> = emptyList()
var room: String? = null
var type: String? = null
var note: String? = null
loop@ while (true) {
when (val index = decodeElementIndex(descriptor)) {
DECODE_DONE -> break@loop
0 -> uid = decodeStringElement(descriptor, 0)
1 -> start = decodeSerializableElement(descriptor, 1, InstantSerializer)
2 -> end = decodeSerializableElement(descriptor, 2, InstantSerializer)
3 -> module = decodeStringElement(descriptor, 3)
4 -> lecturers = decodeSerializableElement(descriptor, 4, ListSerializer(String.serializer()))
5 -> room = decodeNullableSerializableElement(descriptor, 5, String.serializer().nullable)
6 -> type = decodeNullableSerializableElement(descriptor, 6, String.serializer().nullable)
7 -> note = decodeNullableSerializableElement(descriptor, 7, String.serializer().nullable)
else -> throw SerializationException("Unexpected index $index")
}
}
Lesson(
requireNotNull(uid),
requireNotNull(start),
requireNotNull(end),
requireNotNull(module),
lecturers,
room,
type,
note
)
}
}
}
@OptIn(ExperimentalSerializationApi::class)
@Serializer(forClass = Instant::class)
object InstantSerializer : KSerializer<Instant> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Instant) {
encoder.encodeString("$value")
}
override fun deserialize(decoder: Decoder): Instant {
return Instant.parse(decoder.decodeString())
}
}
您可以像这样在使用序列化程序之前配置它们:
@file:UseSerializers(InstantSerializer::class, LessonSerializer::class)