Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remaining STJ work for .NET 8 #37806

Merged
merged 8 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 8 additions & 42 deletions docs/core/whats-new/dotnet-8.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ The serializer has built-in support for the following additional types.

#### Source generator

.NET 8 includes enhancements of the System.Text.Json [source generator](../../standard/serialization/system-text-json/source-generation.md) that are aimed at making the [Native AOT](../../standard/glossary.md#native-aot) experience on par with the [reflection-based serializer](../../standard/serialization/system-text-json/source-generation-modes.md#overview). For example:
.NET 8 includes enhancements of the System.Text.Json [source generator](../../standard/serialization/system-text-json/source-generation.md) that are aimed at making the [Native AOT](../../standard/glossary.md#native-aot) experience on par with the [reflection-based serializer](../../standard/serialization/system-text-json/reflection-vs-source-generation.md#reflection). For example:

- The source generator now supports serializing types with [`required`](../../standard/serialization/system-text-json/required-properties.md) and [`init`](../../csharp/language-reference/keywords/init.md) properties. These were both already supported in reflection-based serialization.
- Improved formatting of source-generated code.
- <xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute> feature parity with <xref:System.Text.Json.JsonSerializerOptions>. This parity lets you specify serialization configuration at compile time, which ensures that the generated `MyContext.Default` property is preconfigured with all the relevant options set.
- Additional diagnostics (such as `SYSLIB1034` and `SYSLIB1039`).
- <xref:System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute> feature parity with <xref:System.Text.Json.JsonSerializerOptions>. For more information, see [Specify options (source generation)](../../standard/serialization/system-text-json/source-generation.md#specify-options).
- Additional diagnostics (such as [SYSLIB1034](../../fundamentals/syslib-diagnostics/syslib1034.md) and [SYSLIB1039](../../fundamentals/syslib-diagnostics/syslib1039.md)).
- Don't include types of ignored or inaccessible properties.
- Support for nesting `JsonSerializerContext` declarations within arbitrary type kinds.
- Support for compiler-generated or *unspeakable* types in weakly typed source generation scenarios. Since compiler-generated types can't be explicitly specified by the source generator, <xref:System.Text.Json?displayProperty=fullName> now performs nearest-ancestor resolution at run time. This resolution determines the most appropriate supertype with which to serialize the value.
Expand All @@ -98,7 +98,7 @@ The serializer has built-in support for the following additional types.
public partial class MyContext : JsonSerializerContext { }
```

For more information, see [Serialize enum fields as strings](../../standard/serialization/system-text-json/source-generation-modes.md#serialize-enum-fields-as-strings).
For more information, see [Serialize enum fields as strings](../../standard/serialization/system-text-json/source-generation.md#serialize-enum-fields-as-strings).

- New `JsonConverter.Type` property lets you look up the type of a non-generic `JsonConverter` instance:

Expand All @@ -111,21 +111,7 @@ The serializer has built-in support for the following additional types.

##### Chain source generators

The <xref:System.Text.Json.JsonSerializerOptions> class includes a new <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolverChain> property that complements the existing <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolver> property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site&mdash;they can be added after the fact.

<xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolverChain> also lets you introspect the chain or remove components from it. The following code snippet shows an example.

```csharp
var options = new JsonSerializerOptions
{
TypeInfoResolver = JsonTypeInfoResolver.Combine(
ContextA.Default, ContextB.Default, ContextC.Default);
};

options.TypeInfoResolverChain.Count; // 3
options.TypeInfoResolverChain.RemoveAt(0);
options.TypeInfoResolverChain.Count; // 2
```
The <xref:System.Text.Json.JsonSerializerOptions> class includes a new <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolverChain> property that complements the existing <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolver> property. These properties are used in contract customization for chaining source generators. The addition of the new property means that you don't have to specify all chained components at one call site&mdash;they can be added after the fact. <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolverChain> also lets you introspect the chain or remove components from it. For more information, see [Combine source generators](../../standard/serialization/system-text-json/source-generation.md#combine-source-generators).

In addition, <xref:System.Text.Json.JsonSerializerOptions.AddContext%60%601?displayProperty=nameWithType> is now obsolete. It's been superseded by the <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolver> and <xref:System.Text.Json.JsonSerializerOptions.TypeInfoResolverChain> properties. For more information, see [SYSLIB0049](../../fundamentals/syslib-diagnostics/syslib0049.md).

Expand Down Expand Up @@ -165,6 +151,8 @@ var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolic
JsonSerializer.Serialize(new { PropertyName = "value" }, options); // { "property_name" : "value" }
```

For more information, see [Use a built-in naming policy](../../standard/serialization/system-text-json/customize-properties.md#use-a-built-in-naming-policy).

#### Read-only properties

You can now deserialize onto read-only fields or properties (that is, those that don't have a `set` accessor).
Expand Down Expand Up @@ -214,31 +202,9 @@ For more information about the *populate* deserialization behavior, see [Populat

You can now disable using the reflection-based serializer by default. This disablement is useful to avoid accidental rooting of reflection components that aren't even in use, especially in trimmed and Native AOT apps. To disable default reflection-based serialization by requiring that a <xref:System.Text.Json.JsonSerializerOptions> argument be passed to the <xref:System.Text.Json.JsonSerializer> serialization and deserialization methods, set the `JsonSerializerIsReflectionEnabledByDefault` MSBuild property to `false` in your project file.

```xml
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
```

(If the property is set to `false` and you don't pass a configured <xref:System.Text.Json.JsonSerializerOptions> argument, the `Serialize` and `Deserialize` methods throw a <xref:System.NotSupportedException> at run time.)

Use the new <xref:System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault> API to check the value of the feature switch. If you're a library author building on top of <xref:System.Text.Json?displayProperty=fullName>, you can rely on the property to configure your defaults without accidentally rooting reflection components.

```csharp
static JsonSerializerOptions GetDefaultOptions()
{
if (JsonSerializer.IsReflectionEnabledByDefault)
{
// This branch has a dependency on DefaultJsonTypeInfo,
// but it will get trimmed away if the feature switch is disabled.
return new()
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower,
}
}

return new() { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower };
}
```
For more information, see [Disable reflection defaults](../../standard/serialization/system-text-json/source-generation.md#disable-reflection-defaults).

#### New JsonNode API methods

Expand Down
2 changes: 2 additions & 0 deletions docs/fundamentals/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ items:
- name: Source generation
items:
- name: Reflection vs. source generation
href: ../standard/serialization/system-text-json/reflection-vs-source-generation.md
- name: Source-generation modes
href: ../standard/serialization/system-text-json/source-generation-modes.md
- name: Use source generation
href: ../standard/serialization/system-text-json/source-generation.md
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ The resulting JSON looks like the following example:
}
```

To use the converter with source generation, see [Serialize enum fields as strings](source-generation-modes.md#serialize-enum-fields-as-strings).
To use the converter with source generation, see [Serialize enum fields as strings](source-generation.md#serialize-enum-fields-as-strings).

:::zone-end

Expand Down
7 changes: 6 additions & 1 deletion docs/standard/serialization/system-text-json/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ title: "Serialize and deserialize JSON using C# - .NET"
description: This overview describes the System.Text.Json namespace functionality for serializing to and deserializing from JSON in .NET.
ms.date: 10/18/2021
no-loc: [System.Text.Json, Newtonsoft.Json]
dev_langs:
- CSharp
- VB
helpviewer_keywords:
- "JSON serialization"
- "serializing objects"
Expand Down Expand Up @@ -58,7 +61,9 @@ There are also extension methods for System.Text.Json on [HttpContent](xref:Syst

## Reflection vs. source generation

By default, `System.Text.Json` uses [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/) to gather the metadata it needs to access properties of objects for serialization and deserialization *at run time*. As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. For more information, see [How to choose reflection or source generation in System.Text.Json](source-generation-modes.md).
By default, `System.Text.Json` gathers the metadata it needs to access properties of objects for serialization and deserialization *at run time* using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size.

For more information, see [Reflection versus source generation](reflection-vs-source-generation.md).

## Security information

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Starting in .NET 8, you can change the deserialization behavior to modify (*popu

A struct property must have a setter; otherwise, an <xref:System.InvalidOperationException> is thrown at run time.

> [!NOTE]
> The populate behavior currently doesn't work for types that have a parameterized constructor. For more information, see [dotnet/runtime issue 92877](https://github.com/dotnet/runtime/issues/92877).

### Read-only properties

For populating reference properties that are mutable, since the instance that the property references isn't *replaced*, the property doesn't need to have a setter. This behavior means that deserialization can also populate *read-only* properties.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: How to choose reflection or source generation in System.Text.Json
description: "Learn how to choose reflection or source generation in System.Text.Json."
ms.date: 10/30/2023
no-loc: [System.Text.Json]
zone_pivot_groups: dotnet-preview-version
---

# Reflection versus source generation in System.Text.Json

This article explains the differences between reflection and source generation as it relates to `System.Text.Json` serialization. It also provides guidance on how to choose the best approach for your scenario.

## Metadata collection

To serialize or deserialize a type, <xref:System.Text.Json.JsonSerializer> needs information about how to access the members of the type. `JsonSerializer` needs the following information:

* How to access property getters and fields for serialization.
* How to access a constructor, property setters, and fields for deserialization.
* Information about which attributes have been used to customize serialization or deserialization.
* Run-time configuration from <xref:System.Text.Json.JsonSerializerOptions>.

This information is referred to as *metadata*.

## Reflection

By default, `JsonSerializer` collects metadata at run time by using [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/). Whenever `JsonSerializer` has to serialize or deserialize a type for the first time, it collects and caches this metadata. The metadata collection process takes time and uses memory.
gewarren marked this conversation as resolved.
Show resolved Hide resolved

## Source generation

As an alternative, `System.Text.Json` can use the C# [source generation](../../../csharp/roslyn-sdk/source-generators-overview.md) feature to improve performance, reduce private memory usage, and facilitate [assembly trimming](../../../core/deploying/trimming/trim-self-contained.md), which reduces app size. In addition, reflection can't be used in [Native AOT applications](../../../core/deploying/native-aot/index.md), so you must use source generation for those apps.
gewarren marked this conversation as resolved.
Show resolved Hide resolved

Source generation can be used in two modes:

* **Metadata collection mode**

During compilation, System.Text.Json collects the metadata needed for serialization and generates source code files. The generated source code files are automatically compiled as an integral part of the application.
gewarren marked this conversation as resolved.
Show resolved Hide resolved

* **Serialization optimization (fast track) mode**
gewarren marked this conversation as resolved.
Show resolved Hide resolved

<xref:System.Text.Json.JsonSerializer> features that customize the output of serialization, such as naming policies and reference preservation, carry a performance overhead. In serialization optimization mode, System.Text.Json generates optimized code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput.
gewarren marked this conversation as resolved.
Show resolved Hide resolved

Source generation for `System.Text.Json` requires C# 9.0 or a later version.

## Feature comparison

Choose reflection or source-generation modes based on the following benefits that each one offers:

:::zone pivot="dotnet-8-0"

| Benefit | Reflection | Source generation<br/>(Metadata collection mode) | Source generation<br/>(Serialization optimization mode) |
|------------------------------------------------------|------------|---------------------|----------------------------|
| Simpler to code and debug. | ✔️ | ❌ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Supports non-public accessors. | ✔️ | ❌ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Supports all available serialization customizations. | ✔️ | ❌ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Reduces start-up time. | ❌ | ✔️ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Reduces private memory usage. | ❌ | ✔️ | ✔️ |
| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ |
| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ |
| Increases serialization throughput. | ❌ | ❌ | ✔️ |

:::zone-end

:::zone pivot="dotnet-7-0,dotnet-6-0"

| Benefit | Reflection | Source generation:<br/>Metadata collection | Source generation:<br/>Serialization optimization |
|------------------------------------------------------|------------|---------------------|----------------------------|
| Simpler to code and debug. | ✔️ | ❌ | ❌ |
| Supports non-public accessors. | ✔️ | ❌ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Supports required properties. | ✔️ | ❌ | ❌ |
| Supports init-only properties. | ✔️ | ❌ | ❌ |
| Supports all available serialization customizations. | ✔️ | ❌ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Reduces start-up time. | ❌ | ✔️ | ❌ |
gewarren marked this conversation as resolved.
Show resolved Hide resolved
| Reduces private memory usage. | ❌ | ✔️ | ✔️ |
| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ |
| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ |
| Increases serialization throughput. | ❌ | ❌ | ✔️ |

:::zone-end
Loading
Loading