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 all 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
9 changes: 7 additions & 2 deletions 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 All @@ -22,7 +25,7 @@ For Visual Basic, there are some limitations on what parts of the library you ca

## How to get the library

The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#source-generation---metadata-collection-mode) is built-in as part of the shared framework for .NET 6 and later versions. Use of source generation requires .NET 5 SDK or later.
The library is built-in as part of the shared framework for .NET Core 3.0 and later versions. The [source generation feature](source-generation-modes.md#metadata-based-mode) is built-in as part of the shared framework for .NET 6 and later versions.

For framework versions earlier than .NET Core 3.0, install the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) NuGet package. The package supports:

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,84 @@
---
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, <xref:System.Text.Json.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.

## 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, certain reflection APIs can't be used in [Native AOT applications](../../../core/deploying/native-aot/index.md), so you must use source generation for those apps.

Source generation can be used in two modes:

* **Metadata-based mode**

During compilation, `System.Text.Json` collects the information needed for serialization and generates source code files that populate JSON contract metadata for the requested types.

* **Serialization-optimization (fast path) mode**

<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 serialization code that uses [`Utf8JsonWriter`](use-utf8jsonwriter.md) directly. This optimized or *fast path* code increases serialization throughput.

Fast-path *deserialization* isn't currently available. For more information, see [dotnet/runtime issue 55043](https://github.com/dotnet/runtime/issues/55043).

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-based mode) | Source generation<br/>(Serialization-optimization mode) |
|------------------------------------------------------|------------|---------------------|----------------------------|
| Simpler to code. | ✔️ | ❌ | ❌ |
| Simpler to debug. | ❌ | ✔️ | ✔️ |
| Supports non-public members. | ✔️ | ✔️<sup>*</sup> | ✔️<sup>*</sup> |
| Supports all available serialization customizations. | ✔️ | ❌<sup>†</sup> | ❌<sup>†</sup> |
| Reduces start-up time. | ❌ | ✔️ | ✔️ |
| Reduces private memory usage. | ❌ | ✔️ | ✔️ |
| Eliminates run-time reflection. | ❌ | ✔️ | ✔️ |
| Facilitates trim-safe app size reduction. | ❌ | ✔️ | ✔️ |
| Increases serialization throughput. | ❌ | ❌ | ✔️ |

\* The source generator supports *some* non-public members, for example, internal types in the same assembly.
† Source-generated contracts can be modified using the contract customization API.

:::zone-end

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

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

:::zone-end
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ From the serializer's perspective, these two demarcations are equivalent and bot

- If you're using a programming language other than C# or a down-level version of C#.
- If you only want the requirement to apply to JSON deserialization.
- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#source-generation---metadata-collection-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time.
- If you're using `System.Text.Json` serialization in [source generation](source-generation-modes.md#metadata-based-mode) mode. In this case, your code won't compile if you use the `required` modifier, as source generation occurs at compile time.

The following code snippet shows an example of a property modified with the `required` keyword. This property must be present in the JSON payload for deserialization to succeed.

Expand Down
Loading
Loading