From e3feabf07f0f27108457b397923b7564edc70452 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Sun, 13 Oct 2024 18:57:26 +0200 Subject: [PATCH 1/6] Init plan for docs --- docs/explanations/1-runtime-features.md | 3 +++ docs/explanations/2-compile-time-features.md | 3 +++ .../explanations/3-checking-of-correctness.md | 4 +++ .../4-integrations-with-others.md | 0 docs/explanations/5-performance-benchmarks.md | 6 +++++ docs/explanations/6-impact-on-others.md | 3 +++ ...-to-double-check-safety-and-correctness.md | 5 ++++ .../2-how-to-squize-more-performance.md | 26 +++++++++++++++++++ .../3-how-to-reduce-maintenance-costs.md | 8 ++++++ ...t-and-serialize-raw-JSON-representation.md | 1 + ...ap-JSON-representation-into-JSON-string.md | 1 + .../6-how-to-validate-schemaless-JSON.md | 1 + ...-to-parse-and-serialize-schemaless-JSON.md | 3 +++ docs/index.md | 20 ++++++++++++++ docs/tutorials/1-getting-started.md | 7 +++++ docs/tutorials/2-use-runtime-configuration.md | 6 +++++ .../3-use-compile-time-configuration.md | 4 +++ ...-derive-codecs-for-algebraic-data-types.md | 0 docs/tutorials/5-use-derives-keyword.md | 0 ...eaming-JSON-values-and-huge-JSON-arrays.md | 0 .../7-writing-custom-value-codecs.md | 4 +++ docs/tutorials/8-writing-custom-key-codecs.md | 3 +++ 22 files changed, 108 insertions(+) create mode 100644 docs/explanations/1-runtime-features.md create mode 100644 docs/explanations/2-compile-time-features.md create mode 100644 docs/explanations/3-checking-of-correctness.md create mode 100644 docs/explanations/4-integrations-with-others.md create mode 100644 docs/explanations/5-performance-benchmarks.md create mode 100644 docs/explanations/6-impact-on-others.md create mode 100644 docs/howtos/1-how-to-double-check-safety-and-correctness.md create mode 100644 docs/howtos/2-how-to-squize-more-performance.md create mode 100644 docs/howtos/3-how-to-reduce-maintenance-costs.md create mode 100644 docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md create mode 100644 docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md create mode 100644 docs/howtos/6-how-to-validate-schemaless-JSON.md create mode 100644 docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md create mode 100644 docs/index.md create mode 100644 docs/tutorials/1-getting-started.md create mode 100644 docs/tutorials/2-use-runtime-configuration.md create mode 100644 docs/tutorials/3-use-compile-time-configuration.md create mode 100644 docs/tutorials/4-derive-codecs-for-algebraic-data-types.md create mode 100644 docs/tutorials/5-use-derives-keyword.md create mode 100644 docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md create mode 100644 docs/tutorials/7-writing-custom-value-codecs.md create mode 100644 docs/tutorials/8-writing-custom-key-codecs.md diff --git a/docs/explanations/1-runtime-features.md b/docs/explanations/1-runtime-features.md new file mode 100644 index 000000000..ffa8dc5e9 --- /dev/null +++ b/docs/explanations/1-runtime-features.md @@ -0,0 +1,3 @@ + + +Challenge: Submit an issue or PR with an improvement \ No newline at end of file diff --git a/docs/explanations/2-compile-time-features.md b/docs/explanations/2-compile-time-features.md new file mode 100644 index 000000000..ffa8dc5e9 --- /dev/null +++ b/docs/explanations/2-compile-time-features.md @@ -0,0 +1,3 @@ + + +Challenge: Submit an issue or PR with an improvement \ No newline at end of file diff --git a/docs/explanations/3-checking-of-correctness.md b/docs/explanations/3-checking-of-correctness.md new file mode 100644 index 000000000..a5ef0a7d0 --- /dev/null +++ b/docs/explanations/3-checking-of-correctness.md @@ -0,0 +1,4 @@ +Printing of generated codecs with macro options (implicit val printCodec: CodecMakerConfig.PrintCodec = new CodecMakerConfig.PrintCodec {}) +Using Java decompilers (CFR) + +Challenge: Find a missing test coverage for some condition or hidden feature and submit an issue (or a PR with a fix) \ No newline at end of file diff --git a/docs/explanations/4-integrations-with-others.md b/docs/explanations/4-integrations-with-others.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/explanations/5-performance-benchmarks.md b/docs/explanations/5-performance-benchmarks.md new file mode 100644 index 000000000..8bda74dee --- /dev/null +++ b/docs/explanations/5-performance-benchmarks.md @@ -0,0 +1,6 @@ +How to run JVM and Scala.js benchmarks + +Synthetic (for focusing on parsing/serialization of different value types and collections) + +Real world format/API samples + +Challenge: \ No newline at end of file diff --git a/docs/explanations/6-impact-on-others.md b/docs/explanations/6-impact-on-others.md new file mode 100644 index 000000000..ef5c60779 --- /dev/null +++ b/docs/explanations/6-impact-on-others.md @@ -0,0 +1,3 @@ +framework benchmarks +safety improvements in play-json, spray-json, upickle +fast performance feedback for jackson-module-scala (and underlying jackson-core), circe \ No newline at end of file diff --git a/docs/howtos/1-how-to-double-check-safety-and-correctness.md b/docs/howtos/1-how-to-double-check-safety-and-correctness.md new file mode 100644 index 000000000..770c14129 --- /dev/null +++ b/docs/howtos/1-how-to-double-check-safety-and-correctness.md @@ -0,0 +1,5 @@ +- Check if some security sensitive options of compile-time and runtime configuration are safe for your use cases +- Print and analyze sources of generated codecs (check number of anonymous classes, size of generated methods, etc.) +- Patch jsoniter-scala sources with some instrumentation, build and publish locally (as example to check number of instantiated codecs) + +Challenge: Find a probable correctness or security flaw and submit a bug issue to jsoniter-scala project \ No newline at end of file diff --git a/docs/howtos/2-how-to-squize-more-performance.md b/docs/howtos/2-how-to-squize-more-performance.md new file mode 100644 index 000000000..a9fe49859 --- /dev/null +++ b/docs/howtos/2-how-to-squize-more-performance.md @@ -0,0 +1,26 @@ +Tools to check: +- Load test with realistic or synthetic input using async-profiler in different modes (-e cpu, alloc, wall) +- Write JMH benchmarks with realistic or synthetic input using different profilers (gc, perfnorm, perfasm) +- Decompile byte code with CFR decompiler to Java + +Options to consider: +- Tune sizes of internal buffers (do not rely on defaults) +- Do pretty printing or use exception stack traces only for debugging +- Use reading and writing from/to pre-allocated sub-arrays +- Use short up to 8 field names per case class (not more than 64 characters in total) +- Use ASCII field and class names +- Turn off checking of field duplication (when parsing on client side) +- Avoid using string types for data that could be immediately parsed to UUID, data-time, and numbers +- Prefer arrays (or immutable arrays in Scala 3) for JSON arrays, especially when they have primitive type values +- Prefer discriminator keys and avoid discriminator fields +- Use JSON arrays for some stable data structures with all required values (2D/3D coordinates, price/quantity, etc.) +- In product types define required fields first, then most frequently used optional fields +- In enumeration and sum-types define most frequently used classes/objects first +- Turn off hex dumps for exceptions +- Generate decoders/encoders only (reduce code size for Scala.js) + +Anti-patterns: +- Generation of codecs for intermediate (non-top level) data structures (as an example, overuse of `derives` keyword) +- Generation and wide usage of codecs for primitives, strings, etc. + +Challenge: Print generated codecs and patch them for yet more efficiency, then open an improvement issue in the jsoniter-scala project diff --git a/docs/howtos/3-how-to-reduce-maintenance-costs.md b/docs/howtos/3-how-to-reduce-maintenance-costs.md new file mode 100644 index 000000000..b4375a54f --- /dev/null +++ b/docs/howtos/3-how-to-reduce-maintenance-costs.md @@ -0,0 +1,8 @@ +Approaches to consider: +- Switch to Scala 3 (safer and faster generation of smaller codecs) +- Use data-structures that follow JSON representation as close as possible (don't forget compile-time configuration during derivation or using annotations) +- Use 2 data models for huge projects with different API versions or 3-rd party data structures (use chimney or ducktape for transformation between them) +- Use GraphQL (caliban) for reach and highly customized requests +- Use Smithy (smithy4s-json) for model first approach with cross-language APIs + +Challenge: Use Dependents side section of the https://index.scala-lang.org/plokhotnyuk/jsoniter-scala page to discover and try some other integrations with jsoniter-scala \ No newline at end of file diff --git a/docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md b/docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md new file mode 100644 index 000000000..fe25b0226 --- /dev/null +++ b/docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md @@ -0,0 +1 @@ +api-key signing \ No newline at end of file diff --git a/docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md b/docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md new file mode 100644 index 000000000..d9cd6a0ba --- /dev/null +++ b/docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md @@ -0,0 +1 @@ +OpenRTB native \ No newline at end of file diff --git a/docs/howtos/6-how-to-validate-schemaless-JSON.md b/docs/howtos/6-how-to-validate-schemaless-JSON.md new file mode 100644 index 000000000..839fe5ce8 --- /dev/null +++ b/docs/howtos/6-how-to-validate-schemaless-JSON.md @@ -0,0 +1 @@ +jsontier-scala-examples/example_02.sc \ No newline at end of file diff --git a/docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md b/docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md new file mode 100644 index 000000000..6cf2043a2 --- /dev/null +++ b/docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md @@ -0,0 +1,3 @@ +dijon, jsoniter-scala-circe, play-json-jsoniter + +Challenge: Provide a PR with adding support of Scala 3 for dijon project \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..bc7d2c741 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,20 @@ +1. Goals + +- Security +- Correctness +- Performance +- Productivity + +Using `scala-cli` (or `scala` for latest versions of Scala 3): + +2. Tutorials + +3. How-tos + +4. API docs + +5. Features + +6. Known-issues + +7. Explanations \ No newline at end of file diff --git a/docs/tutorials/1-getting-started.md b/docs/tutorials/1-getting-started.md new file mode 100644 index 000000000..e119069c6 --- /dev/null +++ b/docs/tutorials/1-getting-started.md @@ -0,0 +1,7 @@ +Goal: show the power of auto-derivation + +Example: +1. +Nested case classes with a couple of collections (`Seq` and `Map`) + +Challenge: find concrete (non-abstract) collection from standard Scala library that is not supported yet by auto-derivation \ No newline at end of file diff --git a/docs/tutorials/2-use-runtime-configuration.md b/docs/tutorials/2-use-runtime-configuration.md new file mode 100644 index 000000000..4790f786f --- /dev/null +++ b/docs/tutorials/2-use-runtime-configuration.md @@ -0,0 +1,6 @@ +Examples with runtime configuration options for: +- Pretty printing and stack traces for debugging +- Max buffer sizes for safety +- Preferred buffer sizes and size of exception hex dump for performance + +Challenge: \ No newline at end of file diff --git a/docs/tutorials/3-use-compile-time-configuration.md b/docs/tutorials/3-use-compile-time-configuration.md new file mode 100644 index 000000000..fe3585ced --- /dev/null +++ b/docs/tutorials/3-use-compile-time-configuration.md @@ -0,0 +1,4 @@ +1. CodecMakerConfiguration +2. Static annotations and their priority over CodecMakerConfiguration + +Challenge: \ No newline at end of file diff --git a/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md b/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/5-use-derives-keyword.md b/docs/tutorials/5-use-derives-keyword.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md b/docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/tutorials/7-writing-custom-value-codecs.md b/docs/tutorials/7-writing-custom-value-codecs.md new file mode 100644 index 000000000..046021c98 --- /dev/null +++ b/docs/tutorials/7-writing-custom-value-codecs.md @@ -0,0 +1,4 @@ +Examples: +1. Custom value codec for Base64 +2. Custom value codec JS compatible `Long` values +3. Custom value codec for generic collections \ No newline at end of file diff --git a/docs/tutorials/8-writing-custom-key-codecs.md b/docs/tutorials/8-writing-custom-key-codecs.md new file mode 100644 index 000000000..628162b37 --- /dev/null +++ b/docs/tutorials/8-writing-custom-key-codecs.md @@ -0,0 +1,3 @@ +Examples: +1. Simple key codec for enums +2. Composite key codec for tuples From 6935e5ff3319934c086cb5a9bca228ee25c57174 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Fri, 22 Nov 2024 14:56:32 +0100 Subject: [PATCH 2/6] Rename how-tos directory --- .../1-how-to-double-check-safety-and-correctness.md | 0 docs/{howtos => how-tos}/2-how-to-squize-more-performance.md | 0 docs/{howtos => how-tos}/3-how-to-reduce-maintenance-costs.md | 0 .../4-how-to-extract-and-serialize-raw-JSON-representation.md | 0 .../5-how-to-wrap-JSON-representation-into-JSON-string.md | 0 docs/{howtos => how-tos}/6-how-to-validate-schemaless-JSON.md | 0 .../7-how-to-parse-and-serialize-schemaless-JSON.md | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename docs/{howtos => how-tos}/1-how-to-double-check-safety-and-correctness.md (100%) rename docs/{howtos => how-tos}/2-how-to-squize-more-performance.md (100%) rename docs/{howtos => how-tos}/3-how-to-reduce-maintenance-costs.md (100%) rename docs/{howtos => how-tos}/4-how-to-extract-and-serialize-raw-JSON-representation.md (100%) rename docs/{howtos => how-tos}/5-how-to-wrap-JSON-representation-into-JSON-string.md (100%) rename docs/{howtos => how-tos}/6-how-to-validate-schemaless-JSON.md (100%) rename docs/{howtos => how-tos}/7-how-to-parse-and-serialize-schemaless-JSON.md (100%) diff --git a/docs/howtos/1-how-to-double-check-safety-and-correctness.md b/docs/how-tos/1-how-to-double-check-safety-and-correctness.md similarity index 100% rename from docs/howtos/1-how-to-double-check-safety-and-correctness.md rename to docs/how-tos/1-how-to-double-check-safety-and-correctness.md diff --git a/docs/howtos/2-how-to-squize-more-performance.md b/docs/how-tos/2-how-to-squize-more-performance.md similarity index 100% rename from docs/howtos/2-how-to-squize-more-performance.md rename to docs/how-tos/2-how-to-squize-more-performance.md diff --git a/docs/howtos/3-how-to-reduce-maintenance-costs.md b/docs/how-tos/3-how-to-reduce-maintenance-costs.md similarity index 100% rename from docs/howtos/3-how-to-reduce-maintenance-costs.md rename to docs/how-tos/3-how-to-reduce-maintenance-costs.md diff --git a/docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md b/docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md similarity index 100% rename from docs/howtos/4-how-to-extract-and-serialize-raw-JSON-representation.md rename to docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md diff --git a/docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md b/docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md similarity index 100% rename from docs/howtos/5-how-to-wrap-JSON-representation-into-JSON-string.md rename to docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md diff --git a/docs/howtos/6-how-to-validate-schemaless-JSON.md b/docs/how-tos/6-how-to-validate-schemaless-JSON.md similarity index 100% rename from docs/howtos/6-how-to-validate-schemaless-JSON.md rename to docs/how-tos/6-how-to-validate-schemaless-JSON.md diff --git a/docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md b/docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md similarity index 100% rename from docs/howtos/7-how-to-parse-and-serialize-schemaless-JSON.md rename to docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md From 1b49510e341afa969d9a108235c45ab6fd4c8159 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Fri, 22 Nov 2024 14:57:02 +0100 Subject: [PATCH 3/6] Add the Getting Started tutorial --- docs/tutorials/1-getting-started.md | 210 ++++++++++++++++++++++++- docs/tutorials/1-getting-started.scala | 135 ++++++++++++++++ 2 files changed, 340 insertions(+), 5 deletions(-) create mode 100644 docs/tutorials/1-getting-started.scala diff --git a/docs/tutorials/1-getting-started.md b/docs/tutorials/1-getting-started.md index e119069c6..acbdfb11f 100644 --- a/docs/tutorials/1-getting-started.md +++ b/docs/tutorials/1-getting-started.md @@ -1,7 +1,207 @@ -Goal: show the power of auto-derivation +# Getting started +Let's start our adventure with jsoniter-scala from parsing and serialization of some complex data structure of nested +collections and case classes. -Example: -1. -Nested case classes with a couple of collections (`Seq` and `Map`) +## Prerequisites +In all tutorials we will use [scala-cli](https://scala-cli.virtuslab.org) for running Scala scripts, so you'll need to install it upfront. -Challenge: find concrete (non-abstract) collection from standard Scala library that is not supported yet by auto-derivation \ No newline at end of file +You can use any text editor to copy and paste provided code snippets. Please, also, check Scala CLI Cookbooks +documentation if you use [VSCode](https://scala-cli.virtuslab.org/docs/cookbooks/ide/vscode), [Intellij IDEA](https://scala-cli.virtuslab.org/docs/cookbooks/ide/intellij), or [emacs](https://scala-cli.virtuslab.org/docs/cookbooks/ide/emacs) editors. + +Support of Scala CLI by IDEs is improving over time, so that [IntelliJ IDEA](https://www.jetbrains.com/idea/) with the latest version of Scala +plugin you can try its [improved support for Scala CLI projects](https://blog.jetbrains.com/scala/2024/11/13/intellij-scala-plugin-2024-3-is-out/#scala-cli). + +Latest versions of jsoniter-scala libraries require JDK 11 or above. You can use any of its distributions. + +In all tutorials we will start from a file with the following dependencies and imports: + +```scala +//> using scala 3 +//> using dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core::2.31.3" +//> using compileOnly.dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros::2.31.3" + +import com.github.plokhotnyuk.jsoniter_scala.core._ +import com.github.plokhotnyuk.jsoniter_scala.macros._ +``` + +Please just copy and paste code snippets from the subsequent steps and run by pressing some `Run` button/keystroke in +your IDE or run it using `scala-cli ` command from the terminal. + +Make sure to preserve indentation when copying and pasting because we will use indenting syntax of Scala 3. + +## Definition of a complex data structure + +Let's imagine that we need to generate a JSON representation of some report for a US shop. + +Below is a definition of its data structures and instantiation of some sample data: + +```scala +enum Category extends Enum[Category]: + case Electronics, Fashion, HomeGoods + +case class Product(id: Long, name: String, category: Category, price: BigDecimal, description: String) + +enum OrderStatus extends Enum[OrderStatus]: + case Pending, Shipped, Delivered, Cancelled + +case class OrderItem(product: Product, quantity: Int) + +case class Order(id: Long, customer: Customer, items: List[OrderItem], status: OrderStatus) + +case class Customer(id: Long, name: String, email: String, address: Address) + +case class Address(street: String, city: String, state: String, zip: String) + +enum PaymentType extends Enum[PaymentType]: + case CreditCard, PayPal + +case class PaymentMethod(`type`: PaymentType, details: Map[String, String]/*e.g. card number, expiration date*/) + +case class Payment(method: PaymentMethod, amount: BigDecimal, timestamp: java.time.Instant) + +case class OrderPayment(order: Order, payment: Payment) + +val product1 = Product( + id = 1L, + name = "Apple iPhone 16", + category = Category.Electronics, + price = BigDecimal(999.99), + description = "A high-end smartphone with advanced camera and AI capabilities" +) +val product2 = Product( + id = 2L, + name = "Nike Air Max 270", + category = Category.Fashion, + price = BigDecimal(129.99), + description = "A stylish and comfortable sneaker with a full-length air unit" +) +val product3 = Product( + id = 3L, + name = "KitchenAid Stand Mixer", + category = Category.HomeGoods, + price = BigDecimal(299.99), + description = "A versatile and powerful stand mixer for baking and cooking" +) +val customer1 = Customer( + id = 1L, + name = "John Doe", + email = "john.doe@example.com", + address = Address( + street = "123 Main St", + city = "Anytown", + state = "CA", + zip = "12345" + ) +) +val customer2 = Customer( + id = 2L, + name = "Jane Smith", + email = "jane.smith@example.com", + address = Address( + street = "456 Elm St", + city = "Othertown", + state = "NY", + zip = "67890" + ) +) +val order1 = Order( + id = 1L, + customer = customer1, + items = List( + OrderItem(product1, 1), + OrderItem(product2, 2) + ), + status = OrderStatus.Pending +) +val order2 = Order( + id = 2L, + customer = customer2, + items = List( + OrderItem(product3, 1) + ), + status = OrderStatus.Shipped +) +val paymentMethod1 = PaymentMethod( + `type` = PaymentType.CreditCard, + details = Map( + "card_number" -> "1234-5678-9012-3456", + "expiration_date" -> "12/2026" + ) +) +val paymentMethod2 = PaymentMethod( + `type` = PaymentType.PayPal, + details = Map( + "paypal_id" -> "jane.smith@example.com" + ) +) +val payment1 = Payment( + method = paymentMethod1, + amount = BigDecimal(1259.97), + timestamp = java.time.Instant.parse("2025-01-03T12:30:45Z") +) +val payment2 = Payment( + method = paymentMethod2, + amount = BigDecimal(299.99), + timestamp = java.time.Instant.parse("2025-01-15T19:10:55Z") +) +val orderPayment1 = OrderPayment( + order = order1, + payment = payment1 +) +val orderPayment2 = OrderPayment( + order = order2, + payment = payment2 +) +val report = List( + orderPayment1, + orderPayment2 +) +``` + +## Defining the codec + +To derive a codec the report type (`List[OrderPayment]` type in our case) we will use `JsonCodecMaker.make` macros: +```scala +given JsonValueCodec[List[OrderPayment]] = JsonCodecMaker.make +``` + +An instance of this codec (also known as a type-class instance) is getting to be visible in the scope of subsequent +calls of parsing and serialization methods. + +## Serialization + +Now we are ready to serialize the report. Just need to define some entry point method and call `writeToString`. +We will also print resulting JSON to the system output to see it as a process output: + +```scala +@main def gettingStarted: Unit = + val json = writeToString(report) + println(json) +``` + +From this moment you can run the script and see a long JSON string on the screen. + +## Parsing + +Having the JSON string in memory you can parse it using following lines that should be pasted to the end of the +`gettingStarted` method: +```scala + val parsedReport = readFromString(json) + println(parsedReport) +``` + +Now you can rerun the script and get additionally printed `toString` representation of a report parsed from JSON string. + +If something gone wrong you can pick the final version of [a script for this tutorial](1-getting-started.scala) and then run it. + +## Challenge +Experiment with different types of collections and try to find any collection type from the standard Scala library that +is not supported by `JsonCodecMaker.make` macros to derive codec for serialization *and* parsing. + +## Recap +In this tutorial we learned basics for parsing and serialization of complex nested data structures using `scala-cli`. +Having definition of data structures and their instances in memory we need to: +1. Add dependency usage and package imports of `core` and `macros` modules of jsoniter-scala +2. Define `given` type-class instance of `JsonValueCodec` for top-level data structure +3. Call `writeToString` to serialize an instance of complex data structure to JSON representation +4. Call `readFromString` to parse a complex data structure from JSON representation diff --git a/docs/tutorials/1-getting-started.scala b/docs/tutorials/1-getting-started.scala new file mode 100644 index 000000000..45016567b --- /dev/null +++ b/docs/tutorials/1-getting-started.scala @@ -0,0 +1,135 @@ +//> using scala 3 +//> using dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-core::2.31.3" +//> using compileOnly.dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros::2.31.3" + +import com.github.plokhotnyuk.jsoniter_scala.core._ +import com.github.plokhotnyuk.jsoniter_scala.macros._ + +enum Category extends Enum[Category]: + case Electronics, Fashion, HomeGoods + +case class Product(id: Long, name: String, category: Category, price: BigDecimal, description: String) + +enum OrderStatus extends Enum[OrderStatus]: + case Pending, Shipped, Delivered, Cancelled + +case class OrderItem(product: Product, quantity: Int) + +case class Order(id: Long, customer: Customer, items: List[OrderItem], status: OrderStatus) + +case class Customer(id: Long, name: String, email: String, address: Address) + +case class Address(street: String, city: String, state: String, zip: String) + +enum PaymentType extends Enum[PaymentType]: + case CreditCard, PayPal + +case class PaymentMethod(`type`: PaymentType, details: Map[String, String]/*e.g. card number, expiration date*/) + +case class Payment(method: PaymentMethod, amount: BigDecimal, timestamp: java.time.Instant) + +case class OrderPayment(order: Order, payment: Payment) + +val product1 = Product( + id = 1L, + name = "Apple iPhone 16", + category = Category.Electronics, + price = BigDecimal(999.99), + description = "A high-end smartphone with advanced camera and AI capabilities" +) +val product2 = Product( + id = 2L, + name = "Nike Air Max 270", + category = Category.Fashion, + price = BigDecimal(129.99), + description = "A stylish and comfortable sneaker with a full-length air unit" +) +val product3 = Product( + id = 3L, + name = "KitchenAid Stand Mixer", + category = Category.HomeGoods, + price = BigDecimal(299.99), + description = "A versatile and powerful stand mixer for baking and cooking" +) +val customer1 = Customer( + id = 1L, + name = "John Doe", + email = "john.doe@example.com", + address = Address( + street = "123 Main St", + city = "Anytown", + state = "CA", + zip = "12345" + ) +) +val customer2 = Customer( + id = 2L, + name = "Jane Smith", + email = "jane.smith@example.com", + address = Address( + street = "456 Elm St", + city = "Othertown", + state = "NY", + zip = "67890" + ) +) +val order1 = Order( + id = 1L, + customer = customer1, + items = List( + OrderItem(product1, 1), + OrderItem(product2, 2) + ), + status = OrderStatus.Pending +) +val order2 = Order( + id = 2L, + customer = customer2, + items = List( + OrderItem(product3, 1) + ), + status = OrderStatus.Shipped +) +val paymentMethod1 = PaymentMethod( + `type` = PaymentType.CreditCard, + details = Map( + "card_number" -> "1234-5678-9012-3456", + "expiration_date" -> "12/2026" + ) +) +val paymentMethod2 = PaymentMethod( + `type` = PaymentType.PayPal, + details = Map( + "paypal_id" -> "jane.smith@example.com" + ) +) +val payment1 = Payment( + method = paymentMethod1, + amount = BigDecimal(1259.97), + timestamp = java.time.Instant.parse("2025-01-03T12:30:45Z") +) +val payment2 = Payment( + method = paymentMethod2, + amount = BigDecimal(299.99), + timestamp = java.time.Instant.parse("2025-01-15T19:10:55Z") +) +val orderPayment1 = OrderPayment( + order = order1, + payment = payment1 +) +val orderPayment2 = OrderPayment( + order = order2, + payment = payment2 +) +val report = List( + orderPayment1, + orderPayment2 +) + +given JsonValueCodec[List[OrderPayment]] = JsonCodecMaker.make + +@main def gettingStarted: Unit = + val json = writeToString(report) + println(json) + val parsedReport = readFromString(json) + println(parsedReport) From 870002c61fbdb477dca26f148dd2f022cd993bb0 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Fri, 22 Nov 2024 18:10:44 +0100 Subject: [PATCH 4/6] Add automatic library version update for docs during release --- release.sbt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/release.sbt b/release.sbt index 2d7b901d7..27b9a1e73 100644 --- a/release.sbt +++ b/release.sbt @@ -22,6 +22,11 @@ lazy val updateVersionInReadmeAndExamples: ReleaseStep = { st: State => s"git add $path" !! st.log } + Seq( + "README.md", + "docs/tutorials/1-getting-started.md", + "docs/tutorials/1-getting-started.scala", + ).foreach(updateFile) updateFile("README.md") (1 to 3).foreach(n => updateFile(s"jsoniter-scala-examples/example0$n.sc")) From c66763fbbef26d698006a3f4d6be0e633231e615 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Sat, 23 Nov 2024 10:58:32 +0100 Subject: [PATCH 5/6] Update docs --- ...-to-double-check-safety-and-correctness.md | 2 - .../2-how-to-squize-more-performance.md | 2 - .../3-how-to-reduce-maintenance-costs.md | 2 - ...t-and-serialize-raw-JSON-representation.md | 2 +- ...ap-JSON-representation-into-JSON-string.md | 2 +- .../6-how-to-validate-schemaless-JSON.md | 2 +- ...-to-parse-and-serialize-schemaless-JSON.md | 2 - docs/index.md | 13 +++-- docs/tutorials/1-getting-started.md | 51 +++++++++---------- docs/tutorials/1-getting-started.scala | 33 +++++------- .../2-use-compile-time-configuration.md | 8 +++ docs/tutorials/2-use-runtime-configuration.md | 6 --- .../3-use-compile-time-configuration.md | 4 -- docs/tutorials/3-use-runtime-configuration.md | 11 ++++ ...-derive-codecs-for-algebraic-data-types.md | 6 +++ docs/tutorials/5-use-derives-keyword.md | 7 +++ ...eaming-JSON-values-and-huge-JSON-arrays.md | 7 +++ ...eaming-JSON-values-and-huge-JSON-arrays.md | 0 .../7-write-custom-value-and-key-codecs.md | 11 ++++ .../7-writing-custom-value-codecs.md | 4 -- docs/tutorials/8-writing-custom-key-codecs.md | 3 -- 21 files changed, 95 insertions(+), 83 deletions(-) create mode 100644 docs/tutorials/2-use-compile-time-configuration.md delete mode 100644 docs/tutorials/2-use-runtime-configuration.md delete mode 100644 docs/tutorials/3-use-compile-time-configuration.md create mode 100644 docs/tutorials/3-use-runtime-configuration.md create mode 100644 docs/tutorials/6-parse-streaming-JSON-values-and-huge-JSON-arrays.md delete mode 100644 docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md create mode 100644 docs/tutorials/7-write-custom-value-and-key-codecs.md delete mode 100644 docs/tutorials/7-writing-custom-value-codecs.md delete mode 100644 docs/tutorials/8-writing-custom-key-codecs.md diff --git a/docs/how-tos/1-how-to-double-check-safety-and-correctness.md b/docs/how-tos/1-how-to-double-check-safety-and-correctness.md index 770c14129..4bc3e27d9 100644 --- a/docs/how-tos/1-how-to-double-check-safety-and-correctness.md +++ b/docs/how-tos/1-how-to-double-check-safety-and-correctness.md @@ -1,5 +1,3 @@ - Check if some security sensitive options of compile-time and runtime configuration are safe for your use cases - Print and analyze sources of generated codecs (check number of anonymous classes, size of generated methods, etc.) - Patch jsoniter-scala sources with some instrumentation, build and publish locally (as example to check number of instantiated codecs) - -Challenge: Find a probable correctness or security flaw and submit a bug issue to jsoniter-scala project \ No newline at end of file diff --git a/docs/how-tos/2-how-to-squize-more-performance.md b/docs/how-tos/2-how-to-squize-more-performance.md index a9fe49859..f338e5923 100644 --- a/docs/how-tos/2-how-to-squize-more-performance.md +++ b/docs/how-tos/2-how-to-squize-more-performance.md @@ -22,5 +22,3 @@ Options to consider: Anti-patterns: - Generation of codecs for intermediate (non-top level) data structures (as an example, overuse of `derives` keyword) - Generation and wide usage of codecs for primitives, strings, etc. - -Challenge: Print generated codecs and patch them for yet more efficiency, then open an improvement issue in the jsoniter-scala project diff --git a/docs/how-tos/3-how-to-reduce-maintenance-costs.md b/docs/how-tos/3-how-to-reduce-maintenance-costs.md index b4375a54f..1155fc586 100644 --- a/docs/how-tos/3-how-to-reduce-maintenance-costs.md +++ b/docs/how-tos/3-how-to-reduce-maintenance-costs.md @@ -4,5 +4,3 @@ Approaches to consider: - Use 2 data models for huge projects with different API versions or 3-rd party data structures (use chimney or ducktape for transformation between them) - Use GraphQL (caliban) for reach and highly customized requests - Use Smithy (smithy4s-json) for model first approach with cross-language APIs - -Challenge: Use Dependents side section of the https://index.scala-lang.org/plokhotnyuk/jsoniter-scala page to discover and try some other integrations with jsoniter-scala \ No newline at end of file diff --git a/docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md b/docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md index fe25b0226..7b2d05868 100644 --- a/docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md +++ b/docs/how-tos/4-how-to-extract-and-serialize-raw-JSON-representation.md @@ -1 +1 @@ -api-key signing \ No newline at end of file +Example: api-key signing \ No newline at end of file diff --git a/docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md b/docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md index d9cd6a0ba..c2ad12bac 100644 --- a/docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md +++ b/docs/how-tos/5-how-to-wrap-JSON-representation-into-JSON-string.md @@ -1 +1 @@ -OpenRTB native \ No newline at end of file +Example: OpenRTB native \ No newline at end of file diff --git a/docs/how-tos/6-how-to-validate-schemaless-JSON.md b/docs/how-tos/6-how-to-validate-schemaless-JSON.md index 839fe5ce8..49120f3e2 100644 --- a/docs/how-tos/6-how-to-validate-schemaless-JSON.md +++ b/docs/how-tos/6-how-to-validate-schemaless-JSON.md @@ -1 +1 @@ -jsontier-scala-examples/example_02.sc \ No newline at end of file +Example: jsontier-scala-examples/example_02.sc \ No newline at end of file diff --git a/docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md b/docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md index 6cf2043a2..be3e7b782 100644 --- a/docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md +++ b/docs/how-tos/7-how-to-parse-and-serialize-schemaless-JSON.md @@ -1,3 +1 @@ dijon, jsoniter-scala-circe, play-json-jsoniter - -Challenge: Provide a PR with adding support of Scala 3 for dijon project \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index bc7d2c741..772f414d4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,16 +5,15 @@ - Performance - Productivity -Using `scala-cli` (or `scala` for latest versions of Scala 3): +2. Features -2. Tutorials +3. Tutorials -3. How-tos +4. How-tos -4. API docs +5. API docs + https://www.javadoc.io/doc/com.github.plokhotnyuk.jsoniter-scala -5. Features - 6. Known-issues -7. Explanations \ No newline at end of file +7. Blog posts \ No newline at end of file diff --git a/docs/tutorials/1-getting-started.md b/docs/tutorials/1-getting-started.md index acbdfb11f..84d9d4b33 100644 --- a/docs/tutorials/1-getting-started.md +++ b/docs/tutorials/1-getting-started.md @@ -46,16 +46,15 @@ enum OrderStatus extends Enum[OrderStatus]: case class OrderItem(product: Product, quantity: Int) -case class Order(id: Long, customer: Customer, items: List[OrderItem], status: OrderStatus) +case class Order(id: Long, customer: Customer, items: Seq[OrderItem], status: OrderStatus) case class Customer(id: Long, name: String, email: String, address: Address) case class Address(street: String, city: String, state: String, zip: String) -enum PaymentType extends Enum[PaymentType]: - case CreditCard, PayPal - -case class PaymentMethod(`type`: PaymentType, details: Map[String, String]/*e.g. card number, expiration date*/) +enum PaymentMethod: + case CreditCard(cardNumber: Long, validThru: java.time.YearMonth) extends PaymentMethod + case PayPal(id: String) extends PaymentMethod case class Payment(method: PaymentMethod, amount: BigDecimal, timestamp: java.time.Instant) @@ -107,7 +106,7 @@ val customer2 = Customer( val order1 = Order( id = 1L, customer = customer1, - items = List( + items = Seq( OrderItem(product1, 1), OrderItem(product2, 2) ), @@ -116,23 +115,17 @@ val order1 = Order( val order2 = Order( id = 2L, customer = customer2, - items = List( + items = Seq( OrderItem(product3, 1) ), status = OrderStatus.Shipped ) -val paymentMethod1 = PaymentMethod( - `type` = PaymentType.CreditCard, - details = Map( - "card_number" -> "1234-5678-9012-3456", - "expiration_date" -> "12/2026" - ) +val paymentMethod1 = PaymentMethod.CreditCard( + cardNumber = 1234_5678_9012_3456L, + validThru = java.time.YearMonth.parse("2026-12") ) -val paymentMethod2 = PaymentMethod( - `type` = PaymentType.PayPal, - details = Map( - "paypal_id" -> "jane.smith@example.com" - ) +val paymentMethod2 = PaymentMethod.PayPal( + id = "jane.smith@example.com" ) val payment1 = Payment( method = paymentMethod1, @@ -152,7 +145,7 @@ val orderPayment2 = OrderPayment( order = order2, payment = payment2 ) -val report = List( +val report = Seq( orderPayment1, orderPayment2 ) @@ -160,18 +153,19 @@ val report = List( ## Defining the codec -To derive a codec the report type (`List[OrderPayment]` type in our case) we will use `JsonCodecMaker.make` macros: +Now we need to derive a codec for the report type (`List[OrderPayment]` type in our case). We will use +`JsonCodecMaker.make` macros for that: ```scala -given JsonValueCodec[List[OrderPayment]] = JsonCodecMaker.make +given JsonValueCodec[Seq[OrderPayment]] = JsonCodecMaker.make ``` An instance of this codec (also known as a type-class instance) is getting to be visible in the scope of subsequent -calls of parsing and serialization methods. +calls of parsing and serialization methods. ## Serialization -Now we are ready to serialize the report. Just need to define some entry point method and call `writeToString`. -We will also print resulting JSON to the system output to see it as a process output: +Now we are ready to serialize the report. For that we need to define some entry point method and call `writeToString`. +We will also print resulting JSON to the system output to see it as an output: ```scala @main def gettingStarted: Unit = @@ -190,13 +184,14 @@ Having the JSON string in memory you can parse it using following lines that sho println(parsedReport) ``` -Now you can rerun the script and get additionally printed `toString` representation of a report parsed from JSON string. +Let's rerun the script and get additionally printed `toString` representation of a report parsed from JSON string. -If something gone wrong you can pick the final version of [a script for this tutorial](1-getting-started.scala) and then run it. +If something gone wrong you can pick and run [the final version of a script for this tutorial](1-getting-started.scala). ## Challenge -Experiment with different types of collections and try to find any collection type from the standard Scala library that -is not supported by `JsonCodecMaker.make` macros to derive codec for serialization *and* parsing. +Experiment with the script to use different types of collections instead of `Seq` and try to find any collection type +from the standard Scala library that is not supported by `JsonCodecMaker.make` macros to derive codec for serialization +and parsing. ## Recap In this tutorial we learned basics for parsing and serialization of complex nested data structures using `scala-cli`. diff --git a/docs/tutorials/1-getting-started.scala b/docs/tutorials/1-getting-started.scala index 45016567b..97822313b 100644 --- a/docs/tutorials/1-getting-started.scala +++ b/docs/tutorials/1-getting-started.scala @@ -15,16 +15,15 @@ enum OrderStatus extends Enum[OrderStatus]: case class OrderItem(product: Product, quantity: Int) -case class Order(id: Long, customer: Customer, items: List[OrderItem], status: OrderStatus) +case class Order(id: Long, customer: Customer, items: Seq[OrderItem], status: OrderStatus) case class Customer(id: Long, name: String, email: String, address: Address) case class Address(street: String, city: String, state: String, zip: String) -enum PaymentType extends Enum[PaymentType]: - case CreditCard, PayPal - -case class PaymentMethod(`type`: PaymentType, details: Map[String, String]/*e.g. card number, expiration date*/) +enum PaymentMethod: + case CreditCard(cardNumber: Long, validThru: java.time.YearMonth) extends PaymentMethod + case PayPal(id: String) extends PaymentMethod case class Payment(method: PaymentMethod, amount: BigDecimal, timestamp: java.time.Instant) @@ -76,7 +75,7 @@ val customer2 = Customer( val order1 = Order( id = 1L, customer = customer1, - items = List( + items = Seq( OrderItem(product1, 1), OrderItem(product2, 2) ), @@ -85,23 +84,17 @@ val order1 = Order( val order2 = Order( id = 2L, customer = customer2, - items = List( + items = Seq( OrderItem(product3, 1) ), status = OrderStatus.Shipped ) -val paymentMethod1 = PaymentMethod( - `type` = PaymentType.CreditCard, - details = Map( - "card_number" -> "1234-5678-9012-3456", - "expiration_date" -> "12/2026" - ) +val paymentMethod1 = PaymentMethod.CreditCard( + cardNumber = 1234_5678_9012_3456L, + validThru = java.time.YearMonth.parse("2026-12") ) -val paymentMethod2 = PaymentMethod( - `type` = PaymentType.PayPal, - details = Map( - "paypal_id" -> "jane.smith@example.com" - ) +val paymentMethod2 = PaymentMethod.PayPal( + id = "jane.smith@example.com" ) val payment1 = Payment( method = paymentMethod1, @@ -121,12 +114,12 @@ val orderPayment2 = OrderPayment( order = order2, payment = payment2 ) -val report = List( +val report = Seq( orderPayment1, orderPayment2 ) -given JsonValueCodec[List[OrderPayment]] = JsonCodecMaker.make +given JsonValueCodec[Seq[OrderPayment]] = JsonCodecMaker.make @main def gettingStarted: Unit = val json = writeToString(report) diff --git a/docs/tutorials/2-use-compile-time-configuration.md b/docs/tutorials/2-use-compile-time-configuration.md new file mode 100644 index 000000000..7a05169a1 --- /dev/null +++ b/docs/tutorials/2-use-compile-time-configuration.md @@ -0,0 +1,8 @@ +1. CodecMakerConfiguration (renaming, stringification, enabling of recursion, disabling generation of decoding or encoding implementations, etc.) +2. Static annotations at field and class definitions and their priority over CodecMakerConfiguration + +## Challenge +Experiment with different combinations of compile-time options and find those that are not supported. +Will compiler errors explain why codecs cannot be generated for such options? + +## Recap diff --git a/docs/tutorials/2-use-runtime-configuration.md b/docs/tutorials/2-use-runtime-configuration.md deleted file mode 100644 index 4790f786f..000000000 --- a/docs/tutorials/2-use-runtime-configuration.md +++ /dev/null @@ -1,6 +0,0 @@ -Examples with runtime configuration options for: -- Pretty printing and stack traces for debugging -- Max buffer sizes for safety -- Preferred buffer sizes and size of exception hex dump for performance - -Challenge: \ No newline at end of file diff --git a/docs/tutorials/3-use-compile-time-configuration.md b/docs/tutorials/3-use-compile-time-configuration.md deleted file mode 100644 index fe3585ced..000000000 --- a/docs/tutorials/3-use-compile-time-configuration.md +++ /dev/null @@ -1,4 +0,0 @@ -1. CodecMakerConfiguration -2. Static annotations and their priority over CodecMakerConfiguration - -Challenge: \ No newline at end of file diff --git a/docs/tutorials/3-use-runtime-configuration.md b/docs/tutorials/3-use-runtime-configuration.md new file mode 100644 index 000000000..2d51b3611 --- /dev/null +++ b/docs/tutorials/3-use-runtime-configuration.md @@ -0,0 +1,11 @@ +Examples with runtime configuration options for: +- Pretty printing and stack traces for debugging +- Max buffer sizes for safety when parsing from `java.io.InputStream` (or `java.nio.DirectByteBuffer`) +- Buffer sizes and disabling of exception hex dump for performance + +## Challenge +Serialize the following string to JSON representation using `writeToString` and then convert resulting string to +byte array using some non UTF-8 charset and then parse it back using `readFromByteArray`. Will jsoniter-scala +parser throw an error with a helpful message? + +## Recap \ No newline at end of file diff --git a/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md b/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md index e69de29bb..8d69ac21a 100644 --- a/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md +++ b/docs/tutorials/4-derive-codecs-for-algebraic-data-types.md @@ -0,0 +1,6 @@ +Scala 3 enums with case classes types +Compile-time configuration of discriminator encoding and mapping of type names + +## Challenge + +## Recap \ No newline at end of file diff --git a/docs/tutorials/5-use-derives-keyword.md b/docs/tutorials/5-use-derives-keyword.md index e69de29bb..59bed915a 100644 --- a/docs/tutorials/5-use-derives-keyword.md +++ b/docs/tutorials/5-use-derives-keyword.md @@ -0,0 +1,7 @@ +Use inlined CodecMakerConfiguration +Use static annotations and their priority over CodecMakerConfiguration +Use derives on top-level data structures + +## Challenge + +## Recap \ No newline at end of file diff --git a/docs/tutorials/6-parse-streaming-JSON-values-and-huge-JSON-arrays.md b/docs/tutorials/6-parse-streaming-JSON-values-and-huge-JSON-arrays.md new file mode 100644 index 000000000..6c49686f9 --- /dev/null +++ b/docs/tutorials/6-parse-streaming-JSON-values-and-huge-JSON-arrays.md @@ -0,0 +1,7 @@ +Generate ~10GB JSON of streamed values +Parse and handle parsed data without loading the whole input in memory +Do the same with huge JSON array + +## Challenge + +## Recap \ No newline at end of file diff --git a/docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md b/docs/tutorials/6-parsing-streaming-JSON-values-and-huge-JSON-arrays.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/tutorials/7-write-custom-value-and-key-codecs.md b/docs/tutorials/7-write-custom-value-and-key-codecs.md new file mode 100644 index 000000000..c075f125d --- /dev/null +++ b/docs/tutorials/7-write-custom-value-and-key-codecs.md @@ -0,0 +1,11 @@ +Examples: +1. Custom value codec for Base64 +2. Custom value codec for CreditCardNumber +3. Custom value codec JS compatible `Long` values +4. Custom value codec for generic collections +5. Custom key codec for enums +6. Custom key codec for tuples + +## Challenge + +## Recap diff --git a/docs/tutorials/7-writing-custom-value-codecs.md b/docs/tutorials/7-writing-custom-value-codecs.md deleted file mode 100644 index 046021c98..000000000 --- a/docs/tutorials/7-writing-custom-value-codecs.md +++ /dev/null @@ -1,4 +0,0 @@ -Examples: -1. Custom value codec for Base64 -2. Custom value codec JS compatible `Long` values -3. Custom value codec for generic collections \ No newline at end of file diff --git a/docs/tutorials/8-writing-custom-key-codecs.md b/docs/tutorials/8-writing-custom-key-codecs.md deleted file mode 100644 index 628162b37..000000000 --- a/docs/tutorials/8-writing-custom-key-codecs.md +++ /dev/null @@ -1,3 +0,0 @@ -Examples: -1. Simple key codec for enums -2. Composite key codec for tuples From b8ef4e05d689620b5443b64ffb9a167d6ae9fbe9 Mon Sep 17 00:00:00 2001 From: Andriy Plokhotnyuk Date: Mon, 25 Nov 2024 08:03:50 +0100 Subject: [PATCH 6/6] Update docs --- docs/tutorials/2-use-compile-time-configuration.md | 1 + docs/tutorials/5-use-derives-keyword.md | 1 + docs/tutorials/7-write-custom-value-and-key-codecs.md | 6 +++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/2-use-compile-time-configuration.md b/docs/tutorials/2-use-compile-time-configuration.md index 7a05169a1..448746065 100644 --- a/docs/tutorials/2-use-compile-time-configuration.md +++ b/docs/tutorials/2-use-compile-time-configuration.md @@ -1,5 +1,6 @@ 1. CodecMakerConfiguration (renaming, stringification, enabling of recursion, disabling generation of decoding or encoding implementations, etc.) 2. Static annotations at field and class definitions and their priority over CodecMakerConfiguration +3. Codec injection using implicits or givens ## Challenge Experiment with different combinations of compile-time options and find those that are not supported. diff --git a/docs/tutorials/5-use-derives-keyword.md b/docs/tutorials/5-use-derives-keyword.md index 59bed915a..f48c6faec 100644 --- a/docs/tutorials/5-use-derives-keyword.md +++ b/docs/tutorials/5-use-derives-keyword.md @@ -1,6 +1,7 @@ Use inlined CodecMakerConfiguration Use static annotations and their priority over CodecMakerConfiguration Use derives on top-level data structures +Use custom codec injections using implicits or givens ## Challenge diff --git a/docs/tutorials/7-write-custom-value-and-key-codecs.md b/docs/tutorials/7-write-custom-value-and-key-codecs.md index c075f125d..c9f95462b 100644 --- a/docs/tutorials/7-write-custom-value-and-key-codecs.md +++ b/docs/tutorials/7-write-custom-value-and-key-codecs.md @@ -1,8 +1,8 @@ Examples: 1. Custom value codec for Base64 -2. Custom value codec for CreditCardNumber -3. Custom value codec JS compatible `Long` values -4. Custom value codec for generic collections +2. Custom value codec JS compatible `Long` values +3. Custom value codec for type constructors +4. Custom value codec for union types 5. Custom key codec for enums 6. Custom key codec for tuples