Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
sandwwraith committed Aug 28, 2024
2 parents 550e1a8 + e4fa8a3 commit b3cfe56
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 49 deletions.
7 changes: 0 additions & 7 deletions buildSrc/src/main/kotlin/publishing-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,6 @@ tasks.withType<KotlinNativeLink>() {
mustRunAfter(tasks.withType<Sign>().named { it == "sign${targetName}Publication" })
}

// Compatibility with old TeamCity configurations that perform :kotlinx-coroutines-core:bintrayUpload
tasks.register("bintrayUpload") {
dependsOn(tasks.publish)
// This is required for K/N publishing
dependsOn(tasks.publishToMavenLocal)
}

fun MavenPom.configureMavenCentralMetadata() {
name = project.name
description = "Kotlin multiplatform serialization runtime library"
Expand Down
6 changes: 3 additions & 3 deletions core/commonMain/src/kotlinx/serialization/Annotations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ import kotlin.reflect.*
*
* @Serializable
* class RgbExample(
* @Serializable(with = RgbAsHexString::class) p1: RgpPixel, // Serialize as HEX string, e.g. #FFFF00
* @Serializable(with = RgbAsSingleInt::class) p2: RgpPixel, // Serialize as single integer, e.g. 16711680
* p3: RgpPixel // Serialize as 3 short components, e.g. { "red": 255, "green": 255, "blue": 0 }
* @Serializable(with = RgbAsHexString::class) p1: RgbPixel, // Serialize as HEX string, e.g. #FFFF00
* @Serializable(with = RgbAsSingleInt::class) p2: RgbPixel, // Serialize as single integer, e.g. 16711680
* p3: RgbPixel // Serialize as 3 short components, e.g. { "red": 255, "green": 255, "blue": 0 }
* )
* ```
* In this example, each pixel will be serialized using different data representation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ public interface Decoder {

/**
* Decodes the value of type [T] by delegating the decoding process to the given [deserializer].
* For example, `decodeInt` call us equivalent to delegating integer decoding to [Int.serializer][Int.Companion.serializer]:
* `decodeSerializableValue(IntSerializer)`
* For example, `decodeInt` call is equivalent to delegating integer decoding to [Int.serializer][Int.Companion.serializer]:
* `decodeSerializableValue(Int.serializer())`
*/
public fun <T : Any?> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T =
deserializer.deserialize(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public interface Encoder {

/**
* Encodes the [value] of type [T] by delegating the encoding process to the given [serializer].
* For example, `encodeInt` call us equivalent to delegating integer encoding to [Int.serializer][Int.Companion.serializer]:
* For example, `encodeInt` call is equivalent to delegating integer encoding to [Int.serializer][Int.Companion.serializer]:
* `encodeSerializableValue(Int.serializer())`
*/
public fun <T : Any?> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
Expand Down
4 changes: 2 additions & 2 deletions docs/builtin-classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,8 @@ even if they are numbers in Kotlin, as we can see below.

### Unit and singleton objects

The Kotlin builtin `Unit` type is also serializable.
`Unit` is a Kotlin [singleton object](https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html),
The Kotlin builtin [Unit](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/) type is also serializable.
`Unit` is a Kotlin [singleton object](https://kotlinlang.org/docs/object-declarations.html#object-declarations-overview),
and is handled equally with other Kotlin objects.

Conceptually, a singleton is a class with only one instance, meaning that state does not define the object,
Expand Down
8 changes: 4 additions & 4 deletions docs/serialization-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ Once the project is set up, we can start serializing some classes.
* <a name='primitive-serializer'></a>[Primitive serializer](serializers.md#primitive-serializer)
* <a name='delegating-serializers'></a>[Delegating serializers](serializers.md#delegating-serializers)
* <a name='composite-serializer-via-surrogate'></a>[Composite serializer via surrogate](serializers.md#composite-serializer-via-surrogate)
* <a name='hand-written-composite-serializer'></a>[Hand-written composite serializer](serializers.md#hand-written-composite-serializer)
* <a name='handwritten-composite-serializer'></a>[Handwritten composite serializer](serializers.md#handwritten-composite-serializer)
* <a name='sequential-decoding-protocol-experimental'></a>[Sequential decoding protocol (experimental)](serializers.md#sequential-decoding-protocol-experimental)
* <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-a-serializer-on-a-property'></a>[Specifying a serializer on a property](serializers.md#specifying-a-serializer-on-a-property)
* <a name='specifying-a-serializer-for-a-particular-type'></a>[Specifying a serializer for a particular type](serializers.md#specifying-a-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='specifying-a-serializer-globally-using-a-typealias'></a>[Specifying a serializer globally using a typealias](serializers.md#specifying-a-serializer-globally-using-a-typealias)
* <a name='custom-serializers-for-a-generic-type'></a>[Custom serializers for a generic type](serializers.md#custom-serializers-for-a-generic-type)
* <a name='format-specific-serializers'></a>[Format-specific serializers](serializers.md#format-specific-serializers)
* <a name='simultaneous-use-of-plugin-generated-and-custom-serializers'></a>[Simultaneous use of plugin-generated and custom serializers](serializers.md#simultaneous-use-of-plugin-generated-and-custom-serializers)
Expand Down
69 changes: 41 additions & 28 deletions docs/serializers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ In this chapter we'll take a look at serializers in more detail, and we'll see h
* [Primitive serializer](#primitive-serializer)
* [Delegating serializers](#delegating-serializers)
* [Composite serializer via surrogate](#composite-serializer-via-surrogate)
* [Hand-written composite serializer](#hand-written-composite-serializer)
* [Handwritten composite serializer](#handwritten-composite-serializer)
* [Sequential decoding protocol (experimental)](#sequential-decoding-protocol-experimental)
* [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 a serializer on a property](#specifying-a-serializer-on-a-property)
* [Specifying a serializer for a particular type](#specifying-a-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)
* [Specifying a serializer globally using a typealias](#specifying-a-serializer-globally-using-a-typealias)
* [Custom serializers for a generic type](#custom-serializers-for-a-generic-type)
* [Format-specific serializers](#format-specific-serializers)
* [Simultaneous use of plugin-generated and custom serializers](#simultaneous-use-of-plugin-generated-and-custom-serializers)
Expand Down Expand Up @@ -165,9 +165,11 @@ fun main() {

> You can get the full code [here](../guide/example/example-serializer-04.kt).
<!--- TEST
```text
PrimitiveDescriptor(kotlin.Int)
-->
```

<!--- TEST -->

### Constructing collection serializers

Expand All @@ -191,9 +193,11 @@ fun main() {

> You can get the full code [here](../guide/example/example-serializer-05.kt).
<!--- TEST
```text
kotlin.collections.ArrayList(PrimitiveDescriptor(kotlin.String))
-->
```

<!--- TEST -->

### Using top-level serializer function

Expand All @@ -217,14 +221,17 @@ fun main() {

> You can get the full code [here](../guide/example/example-serializer-06.kt).
<!--- TEST
```text
kotlin.collections.LinkedHashMap(PrimitiveDescriptor(kotlin.String), Color(rgb: kotlin.Int))
-->
```

<!--- TEST -->

## Custom serializers

A plugin-generated serializer is convenient, but it may not produce the JSON we want
for such a class as `Color`. Let's study alternatives.
for such a class as `Color`.
Let's study the alternatives.

### Primitive serializer

Expand Down Expand Up @@ -254,7 +261,7 @@ object ColorAsStringSerializer : KSerializer<Color> {
}
```

Serializer has three required pieces.
A serializer has three required pieces.

* The [serialize][SerializationStrategy.serialize] function implements [SerializationStrategy].
It receives an instance of [Encoder] and a value to serialize.
Expand Down Expand Up @@ -419,10 +426,10 @@ class ColorIntArraySerializer : KSerializer<Color> {
Note that we can't use default `Color.serializer().descriptor` here because formats that rely
on the schema may think that we would call `encodeInt` instead of `encodeSerializableValue`.
Neither we can use `IntArraySerializer().descriptor` directly — otherwise, formats that handle int arrays specially
can't tell if `value` is really a `IntArray` or a `Color`. Don't worry, this optimization would still kick in
when serializing actual underlying int array.
can't tell if `value` is really an `IntArray` or a `Color`.
Don't worry, this optimization would still kick in when serializing the actual underlying int array.

> Example of how format can treat arrays specially is shown in the [formats guide](formats.md#format-specific-types).
> An example of how a format can treat arrays specially is shown in the [formats guide](formats.md#format-specific-types).
Now we can use the serializer:

Expand Down Expand Up @@ -518,7 +525,7 @@ fun main() {

<!--- TEST -->

### Hand-written composite serializer
### Handwritten composite serializer

There are some cases where a surrogate solution does not fit. Perhaps we want to avoid the performance
implications of additional allocation, or we want a configurable/dynamic set of properties for the
Expand Down Expand Up @@ -617,10 +624,10 @@ As before, we got the `Color` class represented as a JSON object with three keys
### Sequential decoding protocol (experimental)
The implementation of the `deserialize` function from the previous section works with any format. However,
some formats either always store all the complex data in order, or only do so sometimes (JSON always stores
collections in order). With these formats the complex protocol of calling `decodeElementIndex` in the loop is
not needed, and a faster implementation can be used if the [CompositeDecoder.decodeSequentially] function returns `true`.
The plugin-generated serializers are actually conceptually similar to the below code.
some formats either always store all the complex data in order or only do so sometimes (JSON always stores
collections in order). With these formats the complex protocol of calling `decodeElementIndex` in a loop is
unnecessary, and a faster implementation can be used if the [CompositeDecoder.decodeSequentially] function returns `true`.
The plugin-generated serializers are actually conceptually similar to the code below.
<!--- INCLUDE
object ColorAsObjectSerializer : KSerializer<Color> {
Expand Down Expand Up @@ -715,9 +722,15 @@ We cannot bind the `DateAsLongSerializer` serializer to the `Date` class with th
because we don't control the `Date` source code. There are several ways to work around that.

### 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.

The `encodeToXxx` and `decodeFromXxx` functions offer overloaded versions
that accept either a [SerializationStrategy] or [DeserializationStrategy] as their first parameter, respectively.
This feature allows you
to provide a custom serializer for types that aren't annotated with [`@Serializable`][Serializable] by default.
This approach is particularly useful
when working with non-serializable classes like `Date` as the top-level object being serialized.
Here's an example:

```kotlin
fun main() {
Expand All @@ -734,7 +747,7 @@ fun main() {

<!--- TEST -->

### Specifying serializer on a property
### Specifying a serializer on a property

When a property of a non-serializable class, like `Date`, is serialized as part of a serializable class we must supply
its serializer or the code will not compile. This is accomplished using the [`@Serializable`][Serializable] annotation on the property.
Expand Down Expand Up @@ -774,7 +787,7 @@ The `stableReleaseDate` property is serialized with the serialization strategy t

<!--- TEST -->

### Specifying serializer for a particular type
### Specifying a 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.
Expand Down Expand Up @@ -854,7 +867,7 @@ fun main() {

<!--- TEST -->

### Specifying serializer globally using typealias
### Specifying a serializer globally using a typealias

kotlinx.serialization tends to be the always-explicit framework when it comes to serialization strategies: normally,
they should be explicitly mentioned in `@Serializable` annotation. Therefore, we do not provide any kind of global serializer
Expand Down Expand Up @@ -1103,7 +1116,7 @@ class ProgrammingLanguage(
To provide a context, we define a [SerializersModule] instance that describes which serializers shall be used
at run-time to serialize which contextually-serializable classes. This is done using the
[SerializersModule {}][SerializersModule()] builder function, which provides the [SerializersModuleBuilder] DSL to
register serializers. In the below example we use the [contextual][_contextual] function with the serializer. The corresponding
register serializers. In the example below we use the [contextual][_contextual] function with the serializer. The corresponding
class this serializer is defined for is fetched automatically via the `reified` type parameter.
```kotlin
Expand Down Expand Up @@ -1201,7 +1214,7 @@ This gets all the `Project` properties serialized:

<!--- TEST -->

### External serialization uses properties
### External serialization uses properties

As we saw earlier, the regular `@Serializable` annotation creates a serializer so that
[Backing fields are serialized](basic-serialization.md#backing-fields-are-serialized). _External_ serialization using
Expand Down
Loading

0 comments on commit b3cfe56

Please sign in to comment.