Skip to content

Commit 6e5f722

Browse files
authored
Add JSON source-gen mode that emits serialization logic (#53212)
* Add JSON source-gen mode that emits serialization logic * Fix System.Net.Http.Json test issues * Fix System.Text.Json test issues * Make check to determine if fast-path can be used more efficient * Address review feedback * Improve derived-JsonSerializerContext detection and support * Address review feedback; reenable tests, and simplify object metadata init * Fix formatting
1 parent 5f66f88 commit 6e5f722

File tree

77 files changed

+2950
-990
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+2950
-990
lines changed

src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/JsonContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ internal partial class JsonContext : JsonSerializerContext
1313
private static JsonContext s_default;
1414
public static JsonContext Default => s_default ??= new JsonContext(new JsonSerializerOptions());
1515

16-
public JsonContext() : base(null)
16+
public JsonContext() : base(null, null)
1717
{
1818
}
1919

20-
public JsonContext(JsonSerializerOptions options) : base(options)
20+
public JsonContext(JsonSerializerOptions options) : base(options, null)
2121
{
2222
}
2323

src/libraries/System.Net.Http.Json/tests/FunctionalTests/JsonContext/Person.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,14 @@ public JsonTypeInfo<Person> Person
2323
}
2424
else
2525
{
26-
JsonTypeInfo<Person> objectInfo = JsonMetadataServices.CreateObjectInfo<Person>();
27-
_Person = objectInfo;
28-
29-
JsonMetadataServices.InitializeObjectInfo(
30-
objectInfo,
26+
JsonTypeInfo<Person> objectInfo = JsonMetadataServices.CreateObjectInfo<Person>(
3127
Options,
3228
createObjectFunc: static () => new Person(),
3329
PersonPropInitFunc,
34-
default);
30+
default,
31+
serializeFunc: null);
32+
33+
_Person = objectInfo;
3534
}
3635
}
3736

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,10 @@ namespace System.Text.Json.Serialization
66
/// <summary>
77
/// The base class of serialization attributes.
88
/// </summary>
9-
public abstract class JsonAttribute : Attribute { }
9+
#if BUILDING_SOURCE_GENERATOR
10+
internal
11+
#else
12+
public
13+
#endif
14+
abstract class JsonAttribute : Attribute { }
1015
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Text.Json.Serialization
5+
{
6+
/// <summary>
7+
/// The <see cref="Json.JsonNamingPolicy"/> to be used at run-time.
8+
/// </summary>
9+
#if BUILDING_SOURCE_GENERATOR
10+
internal
11+
#else
12+
public
13+
#endif
14+
enum JsonKnownNamingPolicy
15+
{
16+
/// <summary>
17+
/// Specifies that JSON property names should not be converted.
18+
/// </summary>
19+
Unspecified = 0,
20+
21+
/// <summary>
22+
/// Specifies that the built-in <see cref="Json.JsonNamingPolicy.CamelCase"/> be used to convert JSON property names.
23+
/// </summary>
24+
BuiltInCamelCase = 1
25+
}
26+
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ namespace System.Text.Json
66
/// <summary>
77
/// Determines the naming policy used to convert a string-based name to another format, such as a camel-casing format.
88
/// </summary>
9-
public abstract class JsonNamingPolicy
9+
#if BUILDING_SOURCE_GENERATOR
10+
internal
11+
#else
12+
public
13+
#endif
14+
abstract class JsonNamingPolicy
1015
{
1116
/// <summary>
1217
/// Initializes a new instance of <see cref="JsonNamingPolicy"/>.
@@ -18,8 +23,6 @@ protected JsonNamingPolicy() { }
1823
/// </summary>
1924
public static JsonNamingPolicy CamelCase { get; } = new JsonCamelCaseNamingPolicy();
2025

21-
internal static JsonNamingPolicy Default { get; } = new JsonDefaultNamingPolicy();
22-
2326
/// <summary>
2427
/// When overridden in a derived class, converts the specified name according to the policy.
2528
/// </summary>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Text.Json.Serialization
5+
{
6+
/// <summary>
7+
/// Instructs the System.Text.Json source generator to assume the specified
8+
/// options will be used at run-time via <see cref="JsonSerializerOptions"/>.
9+
/// </summary>
10+
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
11+
#if BUILDING_SOURCE_GENERATOR
12+
internal
13+
#else
14+
public
15+
#endif
16+
class JsonSerializerOptionsAttribute : JsonAttribute
17+
{
18+
/// <summary>
19+
/// Specifies the default ignore condition.
20+
/// </summary>
21+
public JsonIgnoreCondition DefaultIgnoreCondition { get; set; }
22+
23+
/// <summary>
24+
/// Specifies whether to ignore read-only fields.
25+
/// </summary>
26+
public bool IgnoreReadOnlyFields { get; set; }
27+
28+
/// <summary>
29+
/// Specifies whether to ignore read-only properties.
30+
/// </summary>
31+
public bool IgnoreReadOnlyProperties { get; set; }
32+
33+
/// <summary>
34+
/// Specifies whether to ignore custom converters provided at run-time.
35+
/// </summary>
36+
public bool IgnoreRuntimeCustomConverters { get; set; }
37+
38+
/// <summary>
39+
/// Specifies whether to include fields for serialization and deserialization.
40+
/// </summary>
41+
public bool IncludeFields { get; set; }
42+
43+
/// <summary>
44+
/// Specifies a built-in naming polices to convert JSON property names with.
45+
/// </summary>
46+
public JsonKnownNamingPolicy NamingPolicy { get; set; }
47+
48+
/// <summary>
49+
/// Specifies whether JSON output should be pretty-printed.
50+
/// </summary>
51+
public bool WriteIndented { get; set; }
52+
}
53+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Text.Json.Serialization
5+
{
6+
/// <summary>
7+
/// The generation mode for the System.Text.Json source generator.
8+
/// </summary>
9+
[Flags]
10+
#if BUILDING_SOURCE_GENERATOR
11+
internal
12+
#else
13+
public
14+
#endif
15+
enum JsonSourceGenerationMode
16+
{
17+
/// <summary>
18+
/// Instructs the JSON source generator to generate serialization logic and type metadata to fallback to
19+
/// when the run-time options are not compatible with the indicated <see cref="JsonSerializerOptionsAttribute"/>.
20+
/// </summary>
21+
/// <remarks>
22+
/// This mode supports all <see cref="JsonSerializer"/> features.
23+
/// </remarks>
24+
MetadataAndSerialization = 0,
25+
26+
/// <summary>
27+
/// Instructs the JSON source generator to generate type-metadata initialization logic.
28+
/// </summary>
29+
/// <remarks>
30+
/// This mode supports all <see cref="JsonSerializer"/> features.
31+
/// </remarks>
32+
Metadata = 1,
33+
34+
/// <summary>
35+
/// Instructs the JSON source generator to generate serialization logic.
36+
/// </summary>
37+
/// <remarks>
38+
/// This mode supports only a subset of <see cref="JsonSerializer"/> features.
39+
/// </remarks>
40+
Serialization = 2
41+
}
42+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Generic;
5+
using System.Text.Json.Serialization;
6+
using System.Text.Json.SourceGeneration.Reflection;
7+
8+
namespace System.Text.Json.SourceGeneration
9+
{
10+
/// <summary>
11+
/// Represents the set of input types and options needed to provide an
12+
/// implementation for a user-provided JsonSerializerContext-derived type.
13+
/// </summary>
14+
internal sealed class ContextGenerationSpec
15+
{
16+
public JsonSerializerOptionsAttribute SerializerOptions { get; init; }
17+
18+
public Type ContextType { get; init; }
19+
20+
public List<TypeGenerationSpec>? RootSerializableTypes { get; init; }
21+
22+
public List<string> ContextClassDeclarationList { get; init; }
23+
24+
/// <summary>
25+
/// Types that we have initiated serialization metadata generation for. A type may be discoverable in the object graph,
26+
/// but not reachable for serialization (e.g. it is [JsonIgnore]'d); thus we maintain a separate cache.
27+
/// </summary>
28+
public HashSet<TypeGenerationSpec> TypesWithMetadataGenerated { get; } = new();
29+
30+
/// <summary>
31+
/// Cache of runtime property names (statically determined) found accross the object graph of the JsonSerializerContext.
32+
/// </summary>
33+
public HashSet<string> RuntimePropertyNames { get; } = new();
34+
35+
public string ContextTypeRef => $"global::{ContextType.GetUniqueCompilableTypeName()}";
36+
}
37+
}

0 commit comments

Comments
 (0)