summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonid Startsev <sandwwraith@users.noreply.github.com>2023-09-11 17:59:29 +0200
committerGitHub <noreply@github.com>2023-09-11 17:59:29 +0200
commitc2303d945bb13caf312c8fab661a9b2b359dfb9f (patch)
tree6e2a670aa673a0f3ebf0f054313fa51f2f8d378b
parent8baa04b4259274305eea6b02f5c5590b44ea126c (diff)
downloadkotlinx.serialization-c2303d945bb13caf312c8fab661a9b2b359dfb9f.tar.gz
Updated code examples and documentation to mention where `@Serializable` annotation can be applied directly to the types. (#2397)
Fixes #2384
-rw-r--r--docs/serialization-guide.md1
-rw-r--r--docs/serializers.md56
-rw-r--r--guide/example/example-serializer-16.kt9
-rw-r--r--guide/example/example-serializer-17.kt19
-rw-r--r--guide/example/example-serializer-18.kt34
-rw-r--r--guide/example/example-serializer-19.kt24
-rw-r--r--guide/example/example-serializer-20.kt15
-rw-r--r--guide/example/example-serializer-21.kt31
-rw-r--r--guide/example/example-serializer-22.kt20
-rw-r--r--guide/example/example-serializer-23.kt28
-rw-r--r--guide/test/SerializersTest.kt27
11 files changed, 170 insertions, 94 deletions
diff --git a/docs/serialization-guide.md b/docs/serialization-guide.md
index 445d32e3..68ede144 100644
--- a/docs/serialization-guide.md
+++ b/docs/serialization-guide.md
@@ -71,6 +71,7 @@ Once the project is set up, we can start serializing some classes.
* <a name='serializing-3rd-party-classes'></a>[Serializing 3rd party classes](serializers.md#serializing-3rd-party-classes)
* <a name='passing-a-serializer-manually'></a>[Passing a serializer manually](serializers.md#passing-a-serializer-manually)
* <a name='specifying-serializer-on-a-property'></a>[Specifying serializer on a property](serializers.md#specifying-serializer-on-a-property)
+ * <a name='specifying-serializer-for-a-particular-type'></a>[Specifying serializer for a particular type](serializers.md#specifying-serializer-for-a-particular-type)
* <a name='specifying-serializers-for-a-file'></a>[Specifying serializers for a file](serializers.md#specifying-serializers-for-a-file)
* <a name='specifying-serializer-globally-using-typealias'></a>[Specifying serializer globally using typealias](serializers.md#specifying-serializer-globally-using-typealias)
* <a name='custom-serializers-for-a-generic-type'></a>[Custom serializers for a generic type](serializers.md#custom-serializers-for-a-generic-type)
diff --git a/docs/serializers.md b/docs/serializers.md
index 2da17fa4..e6bf78e3 100644
--- a/docs/serializers.md
+++ b/docs/serializers.md
@@ -24,6 +24,7 @@ In this chapter we'll take a look at serializers in more detail, and we'll see h
* [Serializing 3rd party classes](#serializing-3rd-party-classes)
* [Passing a serializer manually](#passing-a-serializer-manually)
* [Specifying serializer on a property](#specifying-serializer-on-a-property)
+ * [Specifying serializer for a particular type](#specifying-serializer-for-a-particular-type)
* [Specifying serializers for a file](#specifying-serializers-for-a-file)
* [Specifying serializer globally using typealias](#specifying-serializer-globally-using-typealias)
* [Custom serializers for a generic type](#custom-serializers-for-a-generic-type)
@@ -713,7 +714,7 @@ because we don't control the `Date` source code. There are several ways to work
### Passing a serializer manually
All `encodeToXxx` and `decodeFromXxx` functions have an overload with the first serializer parameter.
-When a non-serializable class, like `Date`, is the top-level class being serialized we can use those.
+When a non-serializable class, like `Date`, is the top-level class being serialized, we can use those.
```kotlin
fun main() {
@@ -770,6 +771,45 @@ The `stableReleaseDate` property is serialized with the serialization strategy t
<!--- TEST -->
+### Specifying serializer for a particular type
+
+[`@Serializable`][Serializable] annotation can also be applied directly to the types.
+This is handy when a class that requires a custom serializer, such as `Date`, happens to be a generic type argument.
+The most common use case for that is when you have a list of dates:
+
+<!--- INCLUDE
+import java.util.Date
+import java.text.SimpleDateFormat
+
+object DateAsLongSerializer : KSerializer<Date> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
+ override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
+ override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
+}
+-->
+
+```kotlin
+@Serializable
+class ProgrammingLanguage(
+ val name: String,
+ val releaseDates: List<@Serializable(DateAsLongSerializer::class) Date>
+)
+
+fun main() {
+ val df = SimpleDateFormat("yyyy-MM-ddX")
+ val data = ProgrammingLanguage("Kotlin", listOf(df.parse("2023-07-06+00"), df.parse("2023-04-25+00"), df.parse("2022-12-28+00")))
+ println(Json.encodeToString(data))
+}
+```
+
+> You can get the full code [here](../guide/example/example-serializer-16.kt).
+
+```text
+{"name":"Kotlin","releaseDates":[1688601600000,1682380800000,1672185600000]}
+```
+
+<!--- TEST -->
+
### Specifying serializers for a file
A serializer for a specific type, like `Date`, can be specified for a whole source code file with the file-level
@@ -803,7 +843,7 @@ fun main() {
println(Json.encodeToString(data))
}
```
-> You can get the full code [here](../guide/example/example-serializer-16.kt).
+> You can get the full code [here](../guide/example/example-serializer-17.kt).
```text
{"name":"Kotlin","stableReleaseDate":1455494400000}
@@ -857,7 +897,7 @@ fun main() {
}
```
-> You can get the full code [here](../guide/example/example-serializer-17.kt).
+> You can get the full code [here](../guide/example/example-serializer-18.kt).
```text
{"stableReleaseDate":"2016-02-15","lastReleaseTimestamp":1657152000000}
@@ -905,7 +945,7 @@ fun main() {
}
```
-> You can get the full code [here](../guide/example/example-serializer-18.kt).
+> You can get the full code [here](../guide/example/example-serializer-19.kt).
The resulting JSON looks like the `Project` class was serialized directly.
@@ -969,7 +1009,7 @@ fun main() {
To actually serialize this class we must provide the corresponding context when calling the `encodeToXxx`/`decodeFromXxx`
functions. Without it we'll get a "Serializer for class 'Date' is not found" exception.
-> See [here](../guide/example/example-serializer-19.kt) for an example that produces that exception.
+> See [here](../guide/example/example-serializer-20.kt) for an example that produces that exception.
<!--- TEST LINES_START
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.
@@ -1028,7 +1068,7 @@ fun main() {
}
```
-> You can get the full code [here](../guide/example/example-serializer-20.kt).
+> You can get the full code [here](../guide/example/example-serializer-21.kt).
```text
{"name":"Kotlin","stableReleaseDate":1455494400000}
```
@@ -1087,7 +1127,7 @@ fun main() {
}
```
-> You can get the full code [here](../guide/example/example-serializer-21.kt).
+> You can get the full code [here](../guide/example/example-serializer-22.kt).
This gets all the `Project` properties serialized:
@@ -1128,7 +1168,7 @@ fun main() {
}
```
-> You can get the full code [here](../guide/example/example-serializer-22.kt).
+> You can get the full code [here](../guide/example/example-serializer-23.kt).
The output is shown below.
diff --git a/guide/example/example-serializer-16.kt b/guide/example/example-serializer-16.kt
index 157208fd..3db0b7ff 100644
--- a/guide/example/example-serializer-16.kt
+++ b/guide/example/example-serializer-16.kt
@@ -1,4 +1,3 @@
-@file:UseSerializers(DateAsLongSerializer::class)
// This file was automatically generated from serializers.md by Knit tool. Do not edit.
package example.exampleSerializer16
@@ -17,9 +16,13 @@ object DateAsLongSerializer : KSerializer<Date> {
}
@Serializable
-class ProgrammingLanguage(val name: String, val stableReleaseDate: Date)
+class ProgrammingLanguage(
+ val name: String,
+ val releaseDates: List<@Serializable(DateAsLongSerializer::class) Date>
+)
fun main() {
- val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
+ val df = SimpleDateFormat("yyyy-MM-ddX")
+ val data = ProgrammingLanguage("Kotlin", listOf(df.parse("2023-07-06+00"), df.parse("2023-04-25+00"), df.parse("2022-12-28+00")))
println(Json.encodeToString(data))
}
diff --git a/guide/example/example-serializer-17.kt b/guide/example/example-serializer-17.kt
index 0ac8dfe8..c5624ed3 100644
--- a/guide/example/example-serializer-17.kt
+++ b/guide/example/example-serializer-17.kt
@@ -1,3 +1,4 @@
+@file:UseSerializers(DateAsLongSerializer::class)
// This file was automatically generated from serializers.md by Knit tool. Do not edit.
package example.exampleSerializer17
@@ -10,27 +11,15 @@ import java.util.Date
import java.text.SimpleDateFormat
object DateAsLongSerializer : KSerializer<Date> {
- override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsLong", PrimitiveKind.LONG)
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
}
-object DateAsSimpleTextSerializer: KSerializer<Date> {
- override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsSimpleText", PrimitiveKind.LONG)
- private val format = SimpleDateFormat("yyyy-MM-dd")
- override fun serialize(encoder: Encoder, value: Date) = encoder.encodeString(format.format(value))
- override fun deserialize(decoder: Decoder): Date = format.parse(decoder.decodeString())
-}
-
-typealias DateAsLong = @Serializable(DateAsLongSerializer::class) Date
-
-typealias DateAsText = @Serializable(DateAsSimpleTextSerializer::class) Date
-
@Serializable
-class ProgrammingLanguage(val stableReleaseDate: DateAsText, val lastReleaseTimestamp: DateAsLong)
+class ProgrammingLanguage(val name: String, val stableReleaseDate: Date)
fun main() {
- val format = SimpleDateFormat("yyyy-MM-ddX")
- val data = ProgrammingLanguage(format.parse("2016-02-15+00"), format.parse("2022-07-07+00"))
+ val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
println(Json.encodeToString(data))
}
diff --git a/guide/example/example-serializer-18.kt b/guide/example/example-serializer-18.kt
index cca857c7..9987e822 100644
--- a/guide/example/example-serializer-18.kt
+++ b/guide/example/example-serializer-18.kt
@@ -6,21 +6,31 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
-@Serializable(with = BoxSerializer::class)
-data class Box<T>(val contents: T)
+import java.util.Date
+import java.text.SimpleDateFormat
+
+object DateAsLongSerializer : KSerializer<Date> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsLong", PrimitiveKind.LONG)
+ override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
+ override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
+}
-class BoxSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<Box<T>> {
- override val descriptor: SerialDescriptor = dataSerializer.descriptor
- override fun serialize(encoder: Encoder, value: Box<T>) = dataSerializer.serialize(encoder, value.contents)
- override fun deserialize(decoder: Decoder) = Box(dataSerializer.deserialize(decoder))
+object DateAsSimpleTextSerializer: KSerializer<Date> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsSimpleText", PrimitiveKind.LONG)
+ private val format = SimpleDateFormat("yyyy-MM-dd")
+ override fun serialize(encoder: Encoder, value: Date) = encoder.encodeString(format.format(value))
+ override fun deserialize(decoder: Decoder): Date = format.parse(decoder.decodeString())
}
-@Serializable
-data class Project(val name: String)
+typealias DateAsLong = @Serializable(DateAsLongSerializer::class) Date
+
+typealias DateAsText = @Serializable(DateAsSimpleTextSerializer::class) Date
+
+@Serializable
+class ProgrammingLanguage(val stableReleaseDate: DateAsText, val lastReleaseTimestamp: DateAsLong)
fun main() {
- val box = Box(Project("kotlinx.serialization"))
- val string = Json.encodeToString(box)
- println(string)
- println(Json.decodeFromString<Box<Project>>(string))
+ val format = SimpleDateFormat("yyyy-MM-ddX")
+ val data = ProgrammingLanguage(format.parse("2016-02-15+00"), format.parse("2022-07-07+00"))
+ println(Json.encodeToString(data))
}
diff --git a/guide/example/example-serializer-19.kt b/guide/example/example-serializer-19.kt
index 4d7c0729..4622665a 100644
--- a/guide/example/example-serializer-19.kt
+++ b/guide/example/example-serializer-19.kt
@@ -6,17 +6,21 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
-import java.util.Date
-import java.text.SimpleDateFormat
+@Serializable(with = BoxSerializer::class)
+data class Box<T>(val contents: T)
-@Serializable
-class ProgrammingLanguage(
- val name: String,
- @Contextual
- val stableReleaseDate: Date
-)
+class BoxSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<Box<T>> {
+ override val descriptor: SerialDescriptor = dataSerializer.descriptor
+ override fun serialize(encoder: Encoder, value: Box<T>) = dataSerializer.serialize(encoder, value.contents)
+ override fun deserialize(decoder: Decoder) = Box(dataSerializer.deserialize(decoder))
+}
+
+@Serializable
+data class Project(val name: String)
fun main() {
- val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
- println(Json.encodeToString(data))
+ val box = Box(Project("kotlinx.serialization"))
+ val string = Json.encodeToString(box)
+ println(string)
+ println(Json.decodeFromString<Box<Project>>(string))
}
diff --git a/guide/example/example-serializer-20.kt b/guide/example/example-serializer-20.kt
index 7ce30e89..38b72e79 100644
--- a/guide/example/example-serializer-20.kt
+++ b/guide/example/example-serializer-20.kt
@@ -6,15 +6,8 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
-import kotlinx.serialization.modules.*
import java.util.Date
import java.text.SimpleDateFormat
-
-object DateAsLongSerializer : KSerializer<Date> {
- override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
- override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
- override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
-}
@Serializable
class ProgrammingLanguage(
@@ -23,13 +16,7 @@ class ProgrammingLanguage(
val stableReleaseDate: Date
)
-private val module = SerializersModule {
- contextual(DateAsLongSerializer)
-}
-
-val format = Json { serializersModule = module }
-
fun main() {
val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
- println(format.encodeToString(data))
+ println(Json.encodeToString(data))
}
diff --git a/guide/example/example-serializer-21.kt b/guide/example/example-serializer-21.kt
index f588a737..9a24b0aa 100644
--- a/guide/example/example-serializer-21.kt
+++ b/guide/example/example-serializer-21.kt
@@ -6,13 +6,30 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
-// NOT @Serializable
-class Project(val name: String, val language: String)
-
-@Serializer(forClass = Project::class)
-object ProjectSerializer
+import kotlinx.serialization.modules.*
+import java.util.Date
+import java.text.SimpleDateFormat
+
+object DateAsLongSerializer : KSerializer<Date> {
+ override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
+ override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
+ override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
+}
+
+@Serializable
+class ProgrammingLanguage(
+ val name: String,
+ @Contextual
+ val stableReleaseDate: Date
+)
+
+private val module = SerializersModule {
+ contextual(DateAsLongSerializer)
+}
+
+val format = Json { serializersModule = module }
fun main() {
- val data = Project("kotlinx.serialization", "Kotlin")
- println(Json.encodeToString(ProjectSerializer, data))
+ val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
+ println(format.encodeToString(data))
}
diff --git a/guide/example/example-serializer-22.kt b/guide/example/example-serializer-22.kt
index 7f098fa7..4eba74b0 100644
--- a/guide/example/example-serializer-22.kt
+++ b/guide/example/example-serializer-22.kt
@@ -6,23 +6,13 @@ import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
-// NOT @Serializable, will use external serializer
-class Project(
- // val in a primary constructor -- serialized
- val name: String
-) {
- var stars: Int = 0 // property with getter & setter -- serialized
-
- val path: String // getter only -- not serialized
- get() = "kotlin/$name"
-
- private var locked: Boolean = false // private, not accessible -- not serialized
-}
-
+// NOT @Serializable
+class Project(val name: String, val language: String)
+
@Serializer(forClass = Project::class)
object ProjectSerializer
fun main() {
- val data = Project("kotlinx.serialization").apply { stars = 9000 }
- println(Json.encodeToString(ProjectSerializer, data))
+ val data = Project("kotlinx.serialization", "Kotlin")
+ println(Json.encodeToString(ProjectSerializer, data))
}
diff --git a/guide/example/example-serializer-23.kt b/guide/example/example-serializer-23.kt
new file mode 100644
index 00000000..4b7de25a
--- /dev/null
+++ b/guide/example/example-serializer-23.kt
@@ -0,0 +1,28 @@
+// This file was automatically generated from serializers.md by Knit tool. Do not edit.
+package example.exampleSerializer23
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+import kotlinx.serialization.encoding.*
+import kotlinx.serialization.descriptors.*
+
+// NOT @Serializable, will use external serializer
+class Project(
+ // val in a primary constructor -- serialized
+ val name: String
+) {
+ var stars: Int = 0 // property with getter & setter -- serialized
+
+ val path: String // getter only -- not serialized
+ get() = "kotlin/$name"
+
+ private var locked: Boolean = false // private, not accessible -- not serialized
+}
+
+@Serializer(forClass = Project::class)
+object ProjectSerializer
+
+fun main() {
+ val data = Project("kotlinx.serialization").apply { stars = 9000 }
+ println(Json.encodeToString(ProjectSerializer, data))
+}
diff --git a/guide/test/SerializersTest.kt b/guide/test/SerializersTest.kt
index c151a150..bda3f7f4 100644
--- a/guide/test/SerializersTest.kt
+++ b/guide/test/SerializersTest.kt
@@ -113,50 +113,57 @@ class SerializersTest {
@Test
fun testExampleSerializer16() {
captureOutput("ExampleSerializer16") { example.exampleSerializer16.main() }.verifyOutputLines(
- "{\"name\":\"Kotlin\",\"stableReleaseDate\":1455494400000}"
+ "{\"name\":\"Kotlin\",\"releaseDates\":[1688601600000,1682380800000,1672185600000]}"
)
}
@Test
fun testExampleSerializer17() {
captureOutput("ExampleSerializer17") { example.exampleSerializer17.main() }.verifyOutputLines(
- "{\"stableReleaseDate\":\"2016-02-15\",\"lastReleaseTimestamp\":1657152000000}"
+ "{\"name\":\"Kotlin\",\"stableReleaseDate\":1455494400000}"
)
}
@Test
fun testExampleSerializer18() {
captureOutput("ExampleSerializer18") { example.exampleSerializer18.main() }.verifyOutputLines(
- "{\"name\":\"kotlinx.serialization\"}",
- "Box(contents=Project(name=kotlinx.serialization))"
+ "{\"stableReleaseDate\":\"2016-02-15\",\"lastReleaseTimestamp\":1657152000000}"
)
}
@Test
fun testExampleSerializer19() {
- captureOutput("ExampleSerializer19") { example.exampleSerializer19.main() }.verifyOutputLinesStart(
- "Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.",
- "Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
+ captureOutput("ExampleSerializer19") { example.exampleSerializer19.main() }.verifyOutputLines(
+ "{\"name\":\"kotlinx.serialization\"}",
+ "Box(contents=Project(name=kotlinx.serialization))"
)
}
@Test
fun testExampleSerializer20() {
- captureOutput("ExampleSerializer20") { example.exampleSerializer20.main() }.verifyOutputLines(
- "{\"name\":\"Kotlin\",\"stableReleaseDate\":1455494400000}"
+ captureOutput("ExampleSerializer20") { example.exampleSerializer20.main() }.verifyOutputLinesStart(
+ "Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.",
+ "Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
)
}
@Test
fun testExampleSerializer21() {
captureOutput("ExampleSerializer21") { example.exampleSerializer21.main() }.verifyOutputLines(
- "{\"name\":\"kotlinx.serialization\",\"language\":\"Kotlin\"}"
+ "{\"name\":\"Kotlin\",\"stableReleaseDate\":1455494400000}"
)
}
@Test
fun testExampleSerializer22() {
captureOutput("ExampleSerializer22") { example.exampleSerializer22.main() }.verifyOutputLines(
+ "{\"name\":\"kotlinx.serialization\",\"language\":\"Kotlin\"}"
+ )
+ }
+
+ @Test
+ fun testExampleSerializer23() {
+ captureOutput("ExampleSerializer23") { example.exampleSerializer23.main() }.verifyOutputLines(
"{\"name\":\"kotlinx.serialization\",\"stars\":9000}"
)
}