In Teil 3 meiner Kotlin-Updates-Serie fasse ich ganz kurz die Neuerungen in der Bibliothek kotlinx.serialization
zusammen, die seit dem Erscheinen meines Kotlin-Buchs erfolgt sind.
Dieser Text bezieht sich auf die folgenden Versionsnummern:
IntelliJ: 2021.1
Kotlin: 1.5.20
kotlinx.serialization: 1.2.1
Gradle: 6.8
Gradle
Der Umstieg von kotlinx.serialization
1.0 auf 1.2 gelingt weitgehend problemlos, sobald einmal build.gradle
passt. Zuerst sollten Sie Gradle selbst auf eine aktuelle Version bringen (Datei graddle/wrapper/gradle-wrapper.properties
). Ich habe das Testprojekt aus dem Buch (Download-Link am Ende des Artikels) auf Version 6.8 aktualisiert. IntelliJ verwendet nach der Änderung in gradle-wrapper.properties
mitunter weiter die alte Gradle-Version und zeigt merkwürdige Fehler an. Abhilfe: Projekt schließen und neu laden.
In build.gradle
müssen Sie nicht nur auf die richtigen Versionen achten, sondern auch, dass es nun getrennte Bibliotheken für unterschiedliche Serialisierungsformate gibt, die extra aufgezählt werden müssen. Wo bisher implementation "...-core:n.n"
reichte, ist jetzt zumindest eine weitere Zeile mit implementation "...-json:n.n"
erforderlich. Das jcenter
-Repository ist zu entfernen, Gradle findet alle erforderlichen Bibliotheken in mavenCentral
.
Ein minimales Muster mit aktuellen Versionsnummern sieht so aus:
// Datei build.gradle
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.5.20'
id 'org.jetbrains.kotlin.plugin.serialization' version "1.5.20"
}
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:1.2.1"
// die folgende Zeile muss bei vorhandenen Projekten hinzugefügt werden!
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
}
compileKotlin {
kotlinOptions.jvmTarget = "11"
}
Neu in Version 1.2
kotlinx.serialization
ist laut JetBrains bis zu doppelt so schnell als die bisherige Implementierung. Außerdem werden diverse neue Kotlin-Dateitypen, u.a. UInt
oder UByte
, jetzt nativ unterstützt. Bei meinen Tests habe ich keine Inkompatibilitäten zwischen Version 1.0 und 1.2 festgestellt.
Zur schon bekannten Annotation @SerialName
, mit der Sie den Zusammenhang zwischen der Variable/Eigenschaft x
in Ihrem Code und dem Serialisierungsfeld y
herstellen konnte, gibt es nun neu auch die Annotation @JsonNames
, um mehrere alternative Namen in der JSON-Datei einer Variablen/Eigenschaft in Ihrem Code zuzuordnen:
// schon bisher möglich
@Serializable
data class Class1(@JsonNames("title") val name: String)
// der JSON-Namen title ist der Eigenschaft name
// der Klasse Class1 zugeordnet
// neu
@Serializable
data class Class2(@JsonNames("title") val name: String)
// die JSON-Namen title UND name sind gleichwertig und werden
// beide der Eigenschaft name der Klasse Class2 zugeordnet
Schließlich wurde die Dokumentation komplett überarbeitet (siehe die Links am Ende des Artikels).
Serialisierung von LocalDateTime
Die Serialisierung von Java-Datentypen LocalDateTime
bzw. von eigenen Datentypen funktioniert nur mit Ihrer Mithilfe. Die Vorgehensweise ist weiterhin experimentell. Sie hat sich in winzigen Details geändert. Zuerst müssen Sie eine Klasse mit den (De)serialisierungs-Funktionen programmieren, die die Schnittstelle KSerialize<typ>
implementiert. Der Datentyp von deserialize
muss jetzt explizit angegeben werden, damit für Kotlin klar ist, ob das Ergebnis auch null
sein kann.
@ExperimentalSerializationApi
@Serializer(LocalDateTime::class)
object LocalDateTimeSerializer : KSerializer<LocalDateTime> {
override fun serialize(encoder: Encoder, value: LocalDateTime) =
encoder.encodeString(value.format(DateTimeFormatter.ISO_DATE_TIME))
// neu: Ergebnistyp muss explizit angegeben werden
override fun deserialize(decoder: Decoder) : LocalDateTime =
LocalDateTime.parse(decoder.decodeString(),
DateTimeFormatter.ISO_DATE_TIME)
}
Damit ist es aber noch nicht getan: Sie müssen Kotlin explizit darauf hinweisen, dass Ihr Serialisierer für einen bestimmten Datentyp verwendet werden soll. Dazu bestehen verschiedene Möglichkeiten. Die in den meisten Fällen einfachste Variante besteht darin, dass Sie am Beginn der Kotlin-Datei mit der Annotation @file:UseSerializers
die gewünschte (De-)Serialisierungsklasse spezifizieren. Diese Einstellung gilt für die gesamte Datei und ist insbesondere dann zweckmäßig, wenn der betreffende Datentyp in vielen Klassen vorkommt.
// am Beginn der Code-Datei angeben
@file:UseSerializers(LocalDateTimeSerializer::class)
IntelliJ zeigt nun eine Warnung an, dass UseSerializers
experimentell ist und mit der Annotation @ExperimentalSerializationApi
gekennzeichnet werden sollte. Dazu habe ich aber keinen Weg gefunden. Sobald ich die Annotation vorangestellt habe, betrachtet der Compiler die gesamte Anweisung als Syntaxfehler.
Quellen/Links
- https://blog.jetbrains.com/kotlin/2021/05/kotlinx-serialization-1-2-released
- https://github.com/Kotlin/kotlinx.serialization
- https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md
- https://kotlin.github.io/kotlinx.serialization
Download
Das aktualisierte Beispielprojekt zu Abschnitt 18.4 können Sie hier herunterladen:
https://kofler.info/uploads/kotlin/kap18-json.zip
Die Kotlin-Updates-Serie
Weitere Kotlin-Update-Artikel finden Sie hier auf meiner Website: