diff --git a/.jekyll-metadata b/.jekyll-metadata index 137709b..b59c459 100644 Binary files a/.jekyll-metadata and b/.jekyll-metadata differ diff --git a/_posts/2024/2024-02-11-dropping-codegen.md b/_posts/2024/2024-02-11-dropping-codegen.md new file mode 100644 index 0000000..26604e5 --- /dev/null +++ b/_posts/2024/2024-02-11-dropping-codegen.md @@ -0,0 +1,86 @@ +--- +title: "Dropping Project Support for Code Generation" +date: 2024-02-11 09:00:00 +1200 +tags: [json-schema, codegen] +toc: true +pin: false +--- + +Some time ago, I released [my first attempt at code generation](/posts/exploring-codegen) from JSON Schemas. However, I've decided to deprecate the library in favor of _Corvus.JsonSchema_. + +When I created _JsonSchema.Net.CodeGeneration_, I knew about _Corvus.JsonSchema_, but I thought it was merely an alternative validator. I didn't truly understand its approach to supporting JSON Schema in .Net. + +Today we're going to take a look at this seeming competitor to see why it actually isn't one. + +## What is _Corvus.JsonSchema_? + +_Corvus.JsonSchema_ is a JSON Schema code generator that bakes validation logic directly into the model. + +To show this, consider the following schema. + +```json +{ + "type": "object", + "properties": { + "foo": { + "type": "integer", + "minimum": 0 + } + } +} +``` + +As one would expect, the library would generate a class with a single property: `int Foo`. But it also generates an `.IsValid()` method that contains all of the validation logic. So if you set `model.Foo = -1`, the `.IsValid()` method will return false. + +However _Corvus.JsonSchema_ has another trick up its sleeve. But before we get into that, it will help to have some understanding of how _System.Text.Json_'s `JsonElement` works. + +## A quick review of `JsonElement` + +Under the hood, `JsonElement` captures the portion of the parsed JSON text by using spans. This has a number of follow-on benefits: + +- By avoiding substringing, there are no additional heap allocations. +- `JsonElement` can be a struct, which further avoids allocations, because it only maintains references to existing memory. +- By holding onto the original text, the value can be interpreted different ways. For example, numbers could be read as `double` or `decimal` or `integer`. + +As an example, consider this string: + +```json +{ "foo": 42, "bar": [ "a string", false ] } +``` + +Five different `JsonElement`s would be created: + +- top-level object +- number value under `foo` +- array value under `bar` +- first element of `bar` array +- second element of `bar` array + +But the kicker is that everything simply references the original string. + +|Value|Backing span| +|:-|:-| +| top-level object | start: 0, length: 44 | +| number value under `foo` | start: 9, length: 2 | +| array value under `bar` | start: 20, length: 21 | +| first element of `bar` array | start: 22, length: 10 | +| second element of `bar` array | start: 34, length: 5 | + +## Back to the validator + +_Corvus.JsonSchema_ builds on this "backing data" pattern that `JsonElement` establishes. Instead of creating a backing field that is the same type that the property exposes, which is the traditional approach for backing fields, the generated code will use a `JsonElement` for the backing field while the property is still strongly typed. + +This means that a model generated by the library can usually be deserialized without any extra allocations, resulting in very high performance! + +> For a much better explanation of what's going on inside the package than what I can provide, I recommend you watch their [showcase video](https://www.youtube.com/watch?v=aTcD-axJBac). +{: .prompt-tip } + +## Keep moving forward + +Ever since I saw that video, I've lamented the fact that it's only available as a `dotnet` tool. I've always envisioned this functionality as a Roslyn source generator. + +To that end, I've paired with [Matthew Adams](https://github.com/mwadams), one of the primary contributors to _Corvus.JsonSchema_, as co-mentor on a [project proposal](https://github.com/json-schema-org/community/issues/614) for JSON Schema's submission to Google's Summer of Code. This project aims to wrap the existing library in an incremental source generator that uses JSON Schema files within a .Net project to automatically generate models at compile time. + +This is a great opportunity to learn about incremental source generators in .Net and build your open source portfolio. If this sounds like a fun project, please make your interest known by commenting on the proposal issue linked above. + +(Even if it's not accepted by GSoc, we're probably going to do it anyway.)