Skip to content

Commit f33405a

Browse files
committed
add docs for aot-support in all schema docs
1 parent 3fb6d30 commit f33405a

File tree

6 files changed

+62
-15
lines changed

6 files changed

+62
-15
lines changed

.jekyll-metadata

8.59 KB
Binary file not shown.

_docs/logic/basics.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ var serializerOptions = new()
158158
};
159159
```
160160

161-
If you don't have any custom rules. You're done. Congratulations.
161+
If you don't have any custom rules, you're done. Congratulations.
162162

163163
If you do have custom rules, you'll want to add `[JsonSerializable]` attributes for those as well.
164164

_docs/schema/basics.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ JSON Schema is expressed as a collection of keywords, each of which provides a s
4545

4646
There are two options when building a schema: defining it inline using the fluent builder and defining it externally and deserializing. Which method you use depends on your specific requirements.
4747

48-
## Deserialization {#schema-deserialization}
48+
## Serialization and Deserialization {#schema-deserialization}
4949

5050
*JsonSchema.Net* schemas are fully serializable.
5151

@@ -61,6 +61,33 @@ var mySchema = JsonSerializer.Deserialize<JsonSchema>(content);
6161

6262
Done.
6363

64+
### Ahead of Time (AOT) compatibility {#aot}
65+
66+
_JsonSchema.Net_ v6 includes updates to support [Native AOT applications](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/). In order to take advantage of this, there are a few things you'll need to do.
67+
68+
First, on your `JsonSerializerContext`, add the following attributes:
69+
70+
```c#
71+
[JsonSerializable(typeof(JsonSchema))]
72+
[JsonSerializable(typeof(EvaluationResults))]
73+
```
74+
75+
It's recommended that you create a single `JsonSerializerOptions` object (or a few if you need different configurations) and reuse it rather than creating them ad-hoc. When you create one, you'll need to configure its `TypeResolverChain` with your serializer context:
76+
77+
```c#
78+
var serializerOptions = new()
79+
{
80+
TypeInfoResolverChain = { MySerializerContext.Default }
81+
};
82+
```
83+
84+
If you don't have any custom keywords, you're done. Congratulations.
85+
86+
If you do have custom keywords, please see the AOT section on the [Vocabularies docs](/schema/vocabs#aot).
87+
88+
> The vocabulary library extensions for _JsonSchema.Net_ are also AOT-compatible and require no further setup.
89+
{: .prompt-tip}
90+
6491
## Inline {#schema-inlining}
6592

6693
There are many reasons why you would want to hard-code your schemas. This library actually hard-codes all of the meta-schemas. Whatever your reason, the `JsonSchemaBuilder` class is going to be your friend.

_docs/schema/schemagen/schema-generation.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ var schema = schemaBuilder.FromType<MyType>().Build();
1616

1717
Done.
1818

19+
> The validating converter described in this document requires AOT-incompatible reflection to operate, so it will not be usable in a Native AOT context.
20+
{: .prompt-warning}
21+
1922
## IMPORTANT {#schema-schemagen-disclaimer}
2023

2124
Ideally, this functionality should be used to create a starting point in authoring a schema. The schemas output by this library should be reviewed by actual people prior to being put into a production system.

_docs/schema/serialization.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
layout: page
33
title: Enhancing Deserialization with JSON Schema
4-
bookmark: Serialization
4+
bookmark: Serialization with Validation
55
permalink: /schema/:title/
66
icon: fas fa-tag
77
order: "01.2"
@@ -15,6 +15,9 @@ Let's walk through it.
1515
> More on JSON Schema support during deserialization can be found on the `json-everything` [blog](https://blog.json-everything.net/posts/deserialization-with-schemas/).
1616
{: .prompt-tip }
1717

18+
> The validating converter described in this document requires AOT-incompatible reflection to operate, so it will not be usable in a Native AOT context.
19+
{: .prompt-warning}
20+
1821
## Setting up the converter {#schema-deserialization-setup}
1922

2023
Custom JSON converters are added via the `JsonSerializationOptions.Converters` property. Any converters in this collection will have priority over the default set of converters that ship with .Net. You can read more about custom converters in their [documentation](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/converters-how-to?pivots=dotnet-7-0).

_docs/schema/vocabs.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ The keywords must still be registered separately (see "Defining Custom Keywords"
104104

105105
It's not always necessary to have a meta-schema for your vocabulary. However, if you want to enable `EvaluationOptions.ValidateMetaschema`, you will need to register it.
106106

107-
# Defining Custom Keywords {#schema-vocabs-custom-keywords}
107+
## Defining Custom Keywords {#schema-vocabs-custom-keywords}
108108

109109
`JsonSchema` has been designed to allow you to create your own keywords. There are several steps that need to be performed to do this.
110110

@@ -122,17 +122,31 @@ And your new keyword is ready to use.
122122

123123
Lastly, remember that the best resource building keywords is [the code](https://github.com/gregsdennis/json-everything/tree/master/JsonSchema) where all of the built-in keywords are defined.
124124

125-
## Evaluation philosophy
125+
### Evaluation philosophy
126126

127127
Starting with version 5 of _JsonSchema.Net_, schema evaluation occurs in two stages: gathering constraints and processing evaluations. Constraints represent all of the work that can be performed by the keyword without an instance, while evaluations complete the work. By separating these stages, _JsonSchema.Net_ can reuse the constraints for subsequent runs, allowing faster run times and fewer memory allocations.
128128

129129
Both stages are defined by implementing the single method on `IJsonSchemaKeyword`.
130130

131-
## 1. Implement `IJsonSchemaKeyword` {#schema-vocabs-custom-keywords-1}
131+
### Ahead of Time (AOT) compatibility {#aot}
132+
133+
_JsonSchema.Net_ v6 includes updates to support [Native AOT applications](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/). Please be sure to read the main AOT section on the [overview page](/schema/basics#aot).
134+
135+
Frist, you'll need to add `[JsonSerializable]` attributes for any custom keywords.
136+
137+
```c#
138+
[JsonSerializable(typeof(MyKeyword))]
139+
```
140+
141+
Second, you'll need to register your keywords using the `SchemaKeywordRegistry.Register<T>(JsonSerializerContext)` method overload, passing in your serializer context, to provide the library access to the `JsonTypeInfo` for your keyword type.
142+
143+
Lastly, due to the dynamic nature of how rules are serialized, your JSON converter MUST implement `IWeaklyTypedJsonConverter` which is defined by _Json.More.Net_. The library also defines a `WeaklyTypeJsonConverter<T>` abstract class that you can use as a base. It's also highly recommended that you take advantage of the `JsonSerializerOptions` [read/write extensions](/more/json-more/#ahead-of-time-aot-compilation-support) provided by _Json.More.Net_.
144+
145+
### 1. Implement `IJsonSchemaKeyword` {#schema-vocabs-custom-keywords-1}
132146

133147
Implementing your keyword will require some initial thought and design around what work the keyword can perform without the instance and what work requires the instance. To illustrate this, let's look at a couple of the existing keyword implementations.
134148

135-
### `maximum`
149+
#### `maximum`
136150

137151
The `maximum` keyword is basically all instance. It asks, "Is the instance a number, and, if so, does it exceed some maximum value?" As such, there's not really much in the way of pre-processing that can be accomplished here that isn't handled in the background. Therefore, all of the work is done by an `Evaluator()` method.
138152

@@ -174,7 +188,7 @@ For `maximum`, evaluation means we check if the value is a number. If not, we i
174188
> `maximum` doesn't have any nested results, but it's still good form to explicitly indicate this.
175189
{: .prompt-info }
176190

177-
### `properties`
191+
#### `properties`
178192

179193
The `properties` keyword presents an opportunity to calculate some things before we have the instance. For example, with this schema
180194

@@ -233,7 +247,7 @@ When we move into the evaluation phase, all of the child constraints that align
233247
> The specification requires that annotations are not reported when validation fails, however this requirement is enforced at the (sub)schema level, not at the keyword level. Annotations are still generally required for sibling keywords (i.e. within the same subschema) to interoperate correctly.
234248
{: .prompt-warning }
235249

236-
### Other variations
250+
#### Other variations
237251

238252
There are a few other variations of keyword interactions, and it may be worth inspecting the code for some of these examples.
239253

@@ -254,7 +268,7 @@ There are a few other variations of keyword interactions, and it may be worth in
254268

255269
Understanding the patterns that already exist will help you build your own keyword implementations.
256270

257-
### Saving evaluation results
271+
#### Saving evaluation results
258272

259273
Once you have validated the instance, you'll need to record the results. These methods are available on the local result object.
260274

@@ -267,7 +281,7 @@ Once you have validated the instance, you'll need to record the results. These
267281

268282
Set any annotations by using `.SetAnnotation()` on the local result object. Generally this needs to be done whether the keyword passes or fails validation. Annotations are stored as a key-value pair, using the keyword name as the key. The value can be anything, but it _should_ be JSON-serializable in order to be rendered properly in the output.
269283

270-
## 2. Implement one of the schema-container interfaces {#schema-vocabs-custom-keywords-2}
284+
### 2. Implement one of the schema-container interfaces {#schema-vocabs-custom-keywords-2}
271285

272286
If your keyword contains one or more subschemas, you'll need to implement one of these:
273287

@@ -278,7 +292,7 @@ If your keyword contains one or more subschemas, you'll need to implement one of
278292

279293
These will be used at the beginning of the first evaluation and during schema registration to traverse all of the subschemas a provide IDs where none is explicitly declared. This goes on to help `$ref` and friends to their job while also making that job faster.
280294

281-
## 3. Apply some attributes {#schema-vocabs-custom-keyword-3}
295+
### 3. Apply some attributes {#schema-vocabs-custom-keyword-3}
282296

283297
*JsonSchema.Net* contains several attributes that you should use to specify some metadata about your keyword.
284298

@@ -287,11 +301,11 @@ These will be used at the beginning of the first evaluation and during schema re
287301
- `SchemaVersion` - Declares a version that supports the keyword. This can be used multiple times to declare additional drafts.
288302
- `Vocabulary` - Declares the ID of the vocabulary which defines the the keyword.
289303

290-
## 4. Register your keyword {#schema-vocabs-custom-keywords-4}
304+
### 4. Register your keyword {#schema-vocabs-custom-keywords-4}
291305

292306
To make *JsonSchema.Net* aware of your keyword, you must register it with `SchemaKeywordRegistry.Register<T>()`. This will enable deserialization.
293307

294-
### Now make it nice to use {#schema-vocabs-custom-extensions}
308+
#### Now make it nice to use {#schema-vocabs-custom-extensions}
295309

296310
To enable the fluent construction interface for your keyword, simply create an extension method on `JsonSchemaBuilder` that adds the keyword and returns the builder. For example, adding a `description` keyword is implemented by this method:
297311

@@ -303,7 +317,7 @@ public static JsonSchemaBuilder Description(this JsonSchemaBuilder builder, stri
303317
}
304318
```
305319

306-
## 5. Create a JSON converter {#schema-vocabs-custom-converter}
320+
### 5. Create a JSON converter {#schema-vocabs-custom-converter}
307321

308322
To enable serialization and deserialization, you'll need to provide the converter for it.
309323

0 commit comments

Comments
 (0)