summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonid Startsev <sandwwraith@gmail.com>2017-11-29 19:47:14 +0300
committerLeonid Startsev <sandwwraith@gmail.com>2017-11-29 19:47:14 +0300
commitc13d9f3265338f018f662ddba312c2e4d5fae5f1 (patch)
treec3bb872e8aeaf87ecc500f7aed1a0b82b93d3592
parent305796c56f7bb514e1e5ebb33b0f1466e23cdca3 (diff)
downloadkotlinx.serialization-c13d9f3265338f018f662ddba312c2e4d5fae5f1.tar.gz
Docs update for 0.3 release
-rw-r--r--README.md118
-rw-r--r--docs/building.md12
-rw-r--r--docs/custom_serializers.md17
-rw-r--r--docs/runtime_usage.md156
4 files changed, 194 insertions, 109 deletions
diff --git a/README.md b/README.md
index 302bb8ff..6834edb2 100644
--- a/README.md
+++ b/README.md
@@ -20,11 +20,23 @@ This project contains the runtime library. Runtime library provides:
* Basic skeleton implementations of these interfaces in which you should override some methods if you want to
implement custom data format (`ElementValueInput/Output`, `NamedValueInput/Output`, `ElementValueTransformer`)
* Some internal classes like built-ins and collections serializers.
-* Ready-to-use [serialization formats](#serialization-formats).
+* Ready-to-use serialization formats.
+* Other useful classes that benefit from serialization framework (e.g. object-to-Map transformer)
You can open example projects for [JVM](example-jvm) or [JS](example-js) to get started playing with it.
-## Example
+## Table of contents
+
+* [Quick example](#quick-example)
+* [Library installing](#setup)
+* [Working in IntelliJ IDEA](#working-in-intellij-idea)
+* [Usage](docs/runtime_usage.md)
+* [More examples of supported Kotlin classes](docs/examples.md)
+* [Writing custom serializers](docs/custom_serializers.md)
+* [Building library and compiler plugin from source](docs/building.md)
+
+
+## Quick example
```kotlin
@@ -40,95 +52,9 @@ fun main(args: Array<String>) {
}
```
-More examples of various kinds of Kotlin classes that can be serialized can be found [here](docs/examples.md).
-
-## Serialization formats
-
-Runtime library provides three ready-to use formats: JSON, CBOR and ProtoBuf.
-
-### JSON usage
-
-JSON format represented by `JSON` class from `kotlinx.serialization.json` package. It has constructor with four optional parameters:
-
-* nonstrict - allow JSON parser skip fields which are not present in class. By default is false.
-* unquoted - means that all field names and other objects (where it's possible) would not be wrapped in quotes. Useful for debugging.
-* indented - classic pretty-printed multiline JSON.
-* indent - size of indent, applicable if parameter above is true.
-
-You can also use one of predefined instances, like `JSON.plain`, `JSON.indented`, `JSON.nonstrict` or `JSON.unquoted`. API is duplicated in companion object, so `JSON.parse(...)` equals to `JSON.plain.parse(...)`
-
-JSON API:
-
-```kotlin
-fun <T> stringify(saver: KSerialSaver<T>, obj: T): String
-inline fun <reified T : Any> stringify(obj: T): String = stringify(T::class.serializer(), obj)
-
-fun <T> parse(loader: KSerialLoader<T>, str: String): T
-inline fun <reified T : Any> parse(str: String): T = parse(T::class.serializer(), str)
-```
-
-`stringify` transforms object to string, `parse` parses. No surprises.
-
-**Note**: because JSON doesn't support maps with keys other than
-strings (and primitives), Kotlin maps with non-trivial key types are serialized as JSON lists.
-
-**Caveat**: `T::class.serializer()` assumes that you use it on class defined as `@Serializable`,
-so it wouldn't work with root-level collections or external serializers out of the box. For external serializers,
-you must [register](docs/custom_serializers.md#registering-and-context) them and create json instance with corresponding scope.
-For collection serializers, see this [feature](https://github.com/Kotlin/kotlinx.serialization/issues/27).
-
-### CBOR usage
-
-`CBOR` object doesn't support any tweaking and provides following functions:
-
-```kotlin
-fun <T : Any> dump(saver: KSerialSaver<T>, obj: T): ByteArray // saves object to bytes
-inline fun <reified T : Any> dump(obj: T): ByteArray // same as above, resolves serializer by itself
-inline fun <reified T : Any> dumps(obj: T): String // dump object and then pretty-print bytes to string
-
-fun <T : Any> load(loader: KSerialLoader<T>, raw: ByteArray): T // load object from bytes
-inline fun <reified T : Any> load(raw: ByteArray): T // save as above
-inline fun <reified T : Any> loads(hex: String): T // inverse operation for dumps
-```
-
-**Note**: CBOR, unlike JSON, supports maps with non-trivial keys,
-and Kotlin maps are serialized as CBOR maps, but some parsers (like `jackson-dataformat-cbor`) don't support this.
-
-### Protobuf usage
-
-Because protobuf relies on serial ids of fields, called 'tags', you have to provide this information,
-using serial annotation `@SerialId`:
-
-```kotlin
-@Serializable
-data class KTestInt32(@SerialId(1) val a: Int)
-```
-
-This class is equivalent to the following proto definition:
-
-```proto
-message Int32 {
- required int32 a = 1;
-}
-```
-
-Note that we are using proto2 semantics, where all fields are explicitly required or optional.
-
-Number format is set via `@ProtoType` annotation. `ProtoNumberType.DEFAULT` is default varint encoding (`intXX`), `SIGNED`
-is signed ZigZag representation (`sintXX`), and `FIXED` is `fixedXX` type. `uintXX` and `sfixedXX` are not supported yet.
-
-Repeated fields represented as lists. Because format spec says that if the list is empty, there will be no elements in the stream with such tag,
-you must explicitly mark any field of list type with `@Optional` annotation with default ` = emptyList()`. Same for maps.
-
-Other known issues and limitations:
-
-* Packed repeated fields are not supported
-* If fields with list tag are going in the arbitrary order, they are not merged into one list, they get overwritten instead.
+To learn more about JSON usage and other formats, see [usage](docs/runtime_usage.md). More examples of various kinds of Kotlin classes that can be serialized can be found [here](docs/examples.md).
-More examples of mappings from proto definitions to Koltin classes can be found in test data:
-[here](runtime/jvm/src/test/proto/test_data.proto) and [here](runtime/jvm/src/test/kotlin/kotlinx/serialization/formats/RandomTests.kt#L47)
-
-## Usage
+## Setup
Using Kotlin Serialization requires Kotlin compiler `1.1.50` or higher, recommended version is `1.2.0`.
Example projects on JVM are available for [Gradle](example-jvm/build.gradle) and [Maven](example-jvm/pom.xml).
@@ -246,22 +172,16 @@ Add dependency on serialization runtime library:
</dependency>
```
-## JavaScript and common
+### JavaScript and common
Replace dependency on `kotlinx-serialization-runtime` with `kotlinx-serialization-runtime-js` or `kotlinx-serialization-runtime-common`
to use it in JavaScript and common projects, respectively.
JavaScript example is located at [`example-js`](example-js) folder.
-## IntelliJ IDEA
+## Working in IntelliJ IDEA
Unfortunately, embedded Kotlin compiler is not supported yet. To be able to run your project with serialization from within IDEA, perform following steps:
`Settings - Build, Execution, Deployment - Build Tools - Gradle - Runner -` tick `Delegate IDE build/run actions to gradle`.
-For maven projects, create separate run configuration.
-
-## Further reading
-
-* [More examples of supported Kotlin classes](docs/examples.md)
-* [Building library from source](docs/building.md)
-* [Writing custom serializers](docs/custom_serializers.md)
+For maven projects, create separate run configuration. \ No newline at end of file
diff --git a/docs/building.md b/docs/building.md
index 438f8dc7..3b09f27e 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -2,7 +2,8 @@
## Runtime library
-To build Kotlin Serialization library from the source run `./gradlew publishToMavenLocal`.
+Kotlin Serialization runtime library itself is a [multiplatform](http://kotlinlang.org/docs/reference/multiplatform.html) project.
+To build library from the source run `./gradlew publishToMavenLocal`.
After that, you can include this library in arbitrary projects like usual gradle dependency:
```gradle
@@ -12,13 +13,14 @@ repositories {
}
dependencies {
- compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.1"
+ compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime"
}
```
-## Compiler plugin
+`master` branch of library should be binary compatible with latest available on bintary compiler plugin. In case you want to test some new features from other branches, which are still in development and may not be compatible in terms of bytecode produced by plugin, you'll need to build the plugin by yourself.
+
+## Compiler plugin
Compiler plugin for Gradle/Maven and IntelliJ plugin are hosted in a separate branch of Kotlin compiler.
-Steps to build it are explained
-[here](https://github.com/JetBrains/kotlin/blob/rr/kotlinx.serialization/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md).
+Sources and steps to build it are located [here](https://github.com/JetBrains/kotlin/blob/rr/kotlinx.serialization/plugins/kotlin-serialization/kotlin-serialization-compiler/).
diff --git a/docs/custom_serializers.md b/docs/custom_serializers.md
index 632d0d86..1b405f5e 100644
--- a/docs/custom_serializers.md
+++ b/docs/custom_serializers.md
@@ -1,6 +1,6 @@
# Writing your own serializers
-The most simple and straightforward way to obtain serializer is to write annotation `@Serializable`
+The most simple and straightforward way to create serializer is to write annotation `@Serializable`
directly on your class:
```kotlin
@@ -10,7 +10,9 @@ class MyData(val s: String)
In this case, compiler plugin will generate for you:
-* Companion object for you class, which implements `KSerializer<MyData>`
+* `.serializer()` method on companion object to obtain serializer. If your class is
+a generic class, this method will have arguments `KSerializer<T1>, KSerializer<T2>`..., where `T1, T2` - your generic type parameters.
+* Special nested object in your class, which implements `KSerializer<MyData>`
* Methods `save` and `load` of interfaces `KSerialSaver` and `KSerialLoader`
* Descriptor property `serialClassDesc` of `KSerializer`
@@ -20,12 +22,13 @@ If you want to customize representation of the class, in most cases, you need to
and `load` methods. Serial descriptor property typically used in generated version of those methods,
so you likely don't need it.
-You can write methods directly on companion object, and serialization plugin will respect them:
-(note you still have to apply annotation, because we need to define `serialClassDesc` even if we don't use it)
+You can write methods directly on companion object, annotate it with `@Serializer(forClass = ...)`, and serialization plugin will respect it as default serializer.
+(note you still have to apply `@Serializable` annotation, because we need to define `serialClassDesc` even if we don't use it)
```kotlin
@Serializable
class MyData(val s: String) {
+ @Serializer(forClass = MyData::class)
companion object /*: KSerializer<MyData> can be omitted or not, if you like*/{
override fun save(output: KOutput, obj: MyData) {
output.writeStringValue(HexConverter.printHexBinary(obj.s.toByteArray()))
@@ -37,6 +40,9 @@ class MyData(val s: String) {
}
}
```
+
+*Note:* this approach is not working yet for generic classes.
+
## External serializers for library classes
Approach above will not work, if you can't modify source code of the class - e.g. it is a Kotlin/Java library class.
@@ -44,6 +50,7 @@ If it is Kotlin class, you can just let the plugin know you want to create seria
```kotlin
// imagine that MyData is a library class
+// if you have generic class, you should use `class` instead of `object`
@Serializer(forClass = MyData::class)
object DataSerializer {}
```
@@ -131,7 +138,7 @@ fun foo(b: B): Pair<String, ByteArray> {
## Overriding serializers
-If you want to give a clue to plugin about which external serializer use for specified property,
+If you want to give a clue to plugin about which serializer use for specified property,
you may use annotation in form `@Serializable(with = SomeKSerializer::class)`:
```kotlin
diff --git a/docs/runtime_usage.md b/docs/runtime_usage.md
new file mode 100644
index 00000000..85d68d61
--- /dev/null
+++ b/docs/runtime_usage.md
@@ -0,0 +1,156 @@
+# Runtime library contents and usage
+
+## Obtaining serializers
+
+Serializers are represented at runtime as `KSerializer<T>`, which in turn, implements interfaces `KSerialSaver<T>` and `KSerialLoader<T>`, where `T` is class you serialize. You don't need to call them by yourself; you just have to pass them properly to serialization format. You can write them on your own (see [custom serializers](custom_serializers.md)) or let the compiler plugin do the dirty work by marking class `@Serializable`. To retrieve the generated serializer, plugin emits special function on companion object called `.serializer()`.
+If your class has generic type arguments, this function will have arguments for specifying serializers on type parameters, because it's impossible to serialize generic class statically in general case:
+
+```kotlin
+@Serializable
+data class Data(val a: Int)
+
+@Serializable
+data class Box<T>(val boxed: T)
+
+val dataSerial : KSerializer<Data> = Data.serializer()
+val boxedDataSerial: KSerializer<Box<Data>> = Box.serializer(dataSerial)
+```
+
+Built-in types, like Int, and standard collections doesn't have that method. You can use corresponding serializers from `kotlinx.serialization.internal` package:
+
+```kotlin
+val i : KSerializer<Int> = IntSerializer // object
+val li: KSerializer<List<Int>> = ArrayListSerializer(IntSerializer) // generic, requires instantiation
+```
+
+For convenience, serializers have extension properties:
+
+```kotlin
+val li: KSerializer<List<Data>> = Data.serializer().list
+val mp: KSerializer<Map<String, Int>> = (StringSerializer to IntSerializer).map // extension on Pair of serializers
+```
+
+In following special case:
+* Class explicitly marked `@Serializable`
+* Class doesn't have generic type arguments
+
+You can obtain serializer from KClass instance: `val d: KSerializer<MyData> = MyData::class.serializer()`. This approach is discouraged in general because of its implicitness, but maybe useful shorthand in some cases.
+
+All external serializers (defined by user) must be [registered](custom_serializers.md#registering-and-context) and instantiated in a user-specific way.
+
+## Serialization formats
+
+Runtime library provides three ready-to use formats: JSON, CBOR and ProtoBuf.
+
+### JSON
+
+JSON format represented by `JSON` class from `kotlinx.serialization.json` package. It has constructor with four optional parameters:
+
+* nonstrict - allow JSON parser skip fields which are not present in class. By default is false.
+* unquoted - means that all field names and other objects (where it's possible) would not be wrapped in quotes. Useful for debugging.
+* indented - classic pretty-printed multiline JSON.
+* indent - size of indent, applicable if parameter above is true.
+
+You can also use one of predefined instances, like `JSON.plain`, `JSON.indented`, `JSON.nonstrict` or `JSON.unquoted`. API is duplicated in companion object, so `JSON.parse(...)` equals to `JSON.plain.parse(...)`
+
+JSON API:
+
+```kotlin
+fun <T> stringify(saver: KSerialSaver<T>, obj: T): String
+inline fun <reified T : Any> stringify(obj: T): String = stringify(T::class.serializer(), obj)
+
+fun <T> parse(loader: KSerialLoader<T>, str: String): T
+inline fun <reified T : Any> parse(str: String): T = parse(T::class.serializer(), str)
+```
+
+`stringify` transforms object to string, `parse` parses. No surprises.
+
+**Note**: because JSON doesn't support maps with keys other than
+strings (and primitives), Kotlin maps with non-trivial key types are serialized as JSON lists.
+
+**Caveat**: `T::class.serializer()` assumes that you use it on class defined as `@Serializable`,
+so it wouldn't work with root-level collections or external serializers out of the box. It's always better to specify serializer [explicitly](#obtaining-serializers).
+
+### CBOR
+
+`CBOR` object doesn't support any tweaking and provides following functions:
+
+```kotlin
+fun <T : Any> dump(saver: KSerialSaver<T>, obj: T): ByteArray // saves object to bytes
+inline fun <reified T : Any> dump(obj: T): ByteArray // same as above, resolves serializer by itself
+inline fun <reified T : Any> dumps(obj: T): String // dump object and then pretty-print bytes to string
+
+fun <T : Any> load(loader: KSerialLoader<T>, raw: ByteArray): T // load object from bytes
+inline fun <reified T : Any> load(raw: ByteArray): T // save as above
+inline fun <reified T : Any> loads(hex: String): T // inverse operation for dumps
+```
+
+**Note**: CBOR, unlike JSON, supports maps with non-trivial keys,
+and Kotlin maps are serialized as CBOR maps, but some parsers (like `jackson-dataformat-cbor`) don't support this.
+
+### Protobuf
+
+Because protobuf relies on serial ids of fields, called 'tags', you have to provide this information,
+using serial annotation `@SerialId`:
+
+```kotlin
+@Serializable
+data class KTestInt32(@SerialId(1) val a: Int)
+```
+
+This class is equivalent to the following proto definition:
+
+```proto
+message Int32 {
+ required int32 a = 1;
+}
+```
+
+Note that we are using proto2 semantics, where all fields are explicitly required or optional.
+
+Number format is set via `@ProtoType` annotation. `ProtoNumberType.DEFAULT` is default varint encoding (`intXX`), `SIGNED`
+is signed ZigZag representation (`sintXX`), and `FIXED` is `fixedXX` type. `uintXX` and `sfixedXX` are not supported yet.
+
+Repeated fields represented as lists. Because format spec says that if the list is empty, there will be no elements in the stream with such tag,
+you must explicitly mark any field of list type with `@Optional` annotation with default ` = emptyList()`. Same for maps.
+
+Other known issues and limitations:
+
+* Packed repeated fields are not supported
+* If fields with list tag are going in the arbitrary order, they are not merged into one list, they get overwritten instead.
+
+More examples of mappings from proto definitions to Koltin classes can be found in test data:
+[here](../runtime/jvm/src/test/proto/test_data.proto) and [here](../runtime/jvm/src/test/kotlin/kotlinx/serialization/formats/RandomTests.kt#L47)
+
+## Useful classes
+
+### Mapper
+
+`Mapper` allows you to serialize/deserialize object to/from map:
+
+```kotlin
+data class Data(val first: Int, val second: String)
+
+val map: Map<String, Any> = Mapper.map(Data(42, "foo")) // mapOf("first" to 42, "second" to "foo")
+```
+
+To get your object back, use `unmap` function. To support objects with nullable values, use `mapNullable` and `unmapNullable`
+
+### Dynamic object parser (JS only)
+
+Allows you to convert JS objects of `dynamic` types into fair correct Kotlin objects.
+
+```kotlin
+@Serializable
+data class Data(val a: Int)
+
+@Serializable
+data class DataWrapper(val s: String, val d: Data?)
+
+val dyn = js("""{s:"foo", d:{a:42}}""")
+val parsed = DynamicObjectParser().parse<DataWrapper>(dyn)
+parsed == DataWrapper("foo", Data(42)) // true
+```
+
+> This feature is still in development and may have some bugs. Parser does not support kotlin maps with keys other than `String`.
+