Skip to content

Commit 71cc95a

Browse files
committed
add post about corvus.jsonschema
1 parent 49c9ef6 commit 71cc95a

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed

.jekyll-metadata

2.32 KB
Binary file not shown.
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
---
2+
title: "Dropping Project Support for Code Generation"
3+
date: 2024-02-11 09:00:00 +1200
4+
tags: [json-schema, codegen]
5+
toc: true
6+
pin: false
7+
---
8+
9+
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_.
10+
11+
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.
12+
13+
Today we're going to take a look at this seeming competitor to see why it actually isn't one.
14+
15+
## What is _Corvus.JsonSchema_?
16+
17+
_Corvus.JsonSchema_ is a JSON Schema code generator that bakes validation logic directly into the model.
18+
19+
To show this, consider the following schema.
20+
21+
```json
22+
{
23+
"type": "object",
24+
"properties": {
25+
"foo": {
26+
"type": "integer",
27+
"minimum": 0
28+
}
29+
}
30+
}
31+
```
32+
33+
As one would expect, the library would generate a class with a single property: `int foo`. But more than mere auto-properties, it generates extra code in the setter to ensure that the model stays within the constraints expressed in the schema, even at runtime.
34+
35+
This means that the setter for `foo` would also contain logic similar to
36+
37+
```c#
38+
if (value < 0)
39+
throw new ArgumentException(nameof(value), "Value must be greater than 0");
40+
41+
_foo = value;
42+
```
43+
44+
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.
45+
46+
## A quick review of `JsonElement`
47+
48+
Under the hood, `JsonElement` captures the portion of the parsed JSON text by using spans. This has a number of follow-on benefits:
49+
50+
- By avoiding substringing, there are no additional heap allocations.
51+
- `JsonElement` can be a struct, which further avoids allocations, because it only maintains references to existing memory.
52+
- 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`.
53+
54+
As an example, consider this string:
55+
56+
```json
57+
{ "foo": 42, "bar": [ "a string", false ] }
58+
```
59+
60+
Five different `JsonElement`s would be created:
61+
62+
- top-level object
63+
- number value under `foo`
64+
- array value under `bar`
65+
- first element of `bar` array
66+
- second element of `bar` array
67+
68+
But the kicker is that everything simply references the original string.
69+
70+
|Value|Backing span|
71+
|:-|:-|
72+
| top-level object | start: 0, length: 44 |
73+
| number value under `foo` | start: 9, length: 2 |
74+
| array value under `bar` | start: 20, length: 21 |
75+
| first element of `bar` array | start: 22, length: 10 |
76+
| second element of `bar` array | start: 34, length: 5 |
77+
78+
## Back to the validator
79+
80+
_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`.
81+
82+
This means that a model generated by the library can usually be deserialized without any extra allocations, resulting in very high performance!
83+
84+
> 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).
85+
{: .prompt-tip }
86+
87+
## Keep moving forward
88+
89+
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.
90+
91+
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.
92+
93+
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.
94+
95+
(Even if it's not accepted by GSoc, we're probably going to do it anyway.)

0 commit comments

Comments
 (0)