Skip to content

Add JSON source-gen mode that emits serialization logic #53212

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

Merged
merged 9 commits into from
May 27, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ internal partial class JsonContext : JsonSerializerContext
private static JsonContext s_default;
public static JsonContext Default => s_default ??= new JsonContext(new JsonSerializerOptions());

public JsonContext() : base(null)
public JsonContext() : base(null, null)
{
}

public JsonContext(JsonSerializerOptions options) : base(options)
public JsonContext(JsonSerializerOptions options) : base(options, null)
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,14 @@ public JsonTypeInfo<Person> Person
}
else
{
JsonTypeInfo<Person> objectInfo = JsonMetadataServices.CreateObjectInfo<Person>();
_Person = objectInfo;

JsonMetadataServices.InitializeObjectInfo(
objectInfo,
JsonTypeInfo<Person> objectInfo = JsonMetadataServices.CreateObjectInfo<Person>(
Options,
createObjectFunc: static () => new Person(),
PersonPropInitFunc,
default);
default,
serializeFunc: null);

_Person = objectInfo;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,10 @@ namespace System.Text.Json.Serialization
/// <summary>
/// The base class of serialization attributes.
/// </summary>
public abstract class JsonAttribute : Attribute { }
#if BUILDING_SOURCE_GENERATOR
internal
#else
public
#endif
abstract class JsonAttribute : Attribute { }
}
26 changes: 26 additions & 0 deletions src/libraries/System.Text.Json/Common/JsonKnownNamingPolicy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Text.Json.Serialization
{
/// <summary>
/// The <see cref="Json.JsonNamingPolicy"/> to be used at run-time.
/// </summary>
#if BUILDING_SOURCE_GENERATOR
internal
#else
public
#endif
enum JsonKnownNamingPolicy
{
/// <summary>
/// Specifies that JSON property names should not be converted.
/// </summary>
Unspecified = 0,

/// <summary>
/// Specifies that the built-in <see cref="Json.JsonNamingPolicy.CamelCase"/> be used to convert JSON property names.
/// </summary>
BuiltInCamelCase = 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ namespace System.Text.Json
/// <summary>
/// Determines the naming policy used to convert a string-based name to another format, such as a camel-casing format.
/// </summary>
public abstract class JsonNamingPolicy
#if BUILDING_SOURCE_GENERATOR
internal
#else
public
#endif
abstract class JsonNamingPolicy
{
/// <summary>
/// Initializes a new instance of <see cref="JsonNamingPolicy"/>.
Expand All @@ -18,8 +23,6 @@ protected JsonNamingPolicy() { }
/// </summary>
public static JsonNamingPolicy CamelCase { get; } = new JsonCamelCaseNamingPolicy();

internal static JsonNamingPolicy Default { get; } = new JsonDefaultNamingPolicy();

/// <summary>
/// When overridden in a derived class, converts the specified name according to the policy.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Text.Json.Serialization
{
/// <summary>
/// Instructs the System.Text.Json source generator to assume the specified
/// options will be used at run-time via <see cref="JsonSerializerOptions"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
#if BUILDING_SOURCE_GENERATOR
internal
#else
public
#endif
class JsonSerializerOptionsAttribute : JsonAttribute
{
/// <summary>
/// Specifies the default ignore condition.
/// </summary>
public JsonIgnoreCondition DefaultIgnoreCondition { get; set; }

/// <summary>
/// Specifies whether to ignore read-only fields.
/// </summary>
public bool IgnoreReadOnlyFields { get; set; }

/// <summary>
/// Specifies whether to ignore read-only properties.
/// </summary>
public bool IgnoreReadOnlyProperties { get; set; }

/// <summary>
/// Specifies whether to ignore custom converters provided at run-time.
/// </summary>
public bool IgnoreRuntimeCustomConverters { get; set; }

/// <summary>
/// Specifies whether to include fields for serialization and deserialization.
/// </summary>
public bool IncludeFields { get; set; }

/// <summary>
/// Specifies a built-in naming polices to convert JSON property names with.
/// </summary>
public JsonKnownNamingPolicy NamingPolicy { get; set; }

/// <summary>
/// Specifies whether JSON output should be pretty-printed.
/// </summary>
public bool WriteIndented { get; set; }
}
}
42 changes: 42 additions & 0 deletions src/libraries/System.Text.Json/Common/JsonSourceGenerationMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Text.Json.Serialization
{
/// <summary>
/// The generation mode for the System.Text.Json source generator.
/// </summary>
[Flags]
#if BUILDING_SOURCE_GENERATOR
internal
#else
public
#endif
enum JsonSourceGenerationMode
{
/// <summary>
/// Instructs the JSON source generator to generate serialization logic and type metadata to fallback to
/// when the run-time options are not compatible with the indicated <see cref="JsonSerializerOptionsAttribute"/>.
/// </summary>
/// <remarks>
/// This mode supports all <see cref="JsonSerializer"/> features.
/// </remarks>
MetadataAndSerialization = 0,

/// <summary>
/// Instructs the JSON source generator to generate type-metadata initialization logic.
/// </summary>
/// <remarks>
/// This mode supports all <see cref="JsonSerializer"/> features.
/// </remarks>
Metadata = 1,

/// <summary>
/// Instructs the JSON source generator to generate serialization logic.
/// </summary>
/// <remarks>
/// This mode supports only a subset of <see cref="JsonSerializer"/> features.
/// </remarks>
Serialization = 2
}
}
37 changes: 37 additions & 0 deletions src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Text.Json.SourceGeneration.Reflection;

namespace System.Text.Json.SourceGeneration
{
/// <summary>
/// Represents the set of input types and options needed to provide an
/// implementation for a user-provided JsonSerializerContext-derived type.
/// </summary>
internal sealed class ContextGenerationSpec
{
public JsonSerializerOptionsAttribute SerializerOptions { get; init; }

public Type ContextType { get; init; }

public List<TypeGenerationSpec>? RootSerializableTypes { get; init; }

public List<string> ContextClassDeclarationList { get; init; }

/// <summary>
/// Types that we have initiated serialization metadata generation for. A type may be discoverable in the object graph,
/// but not reachable for serialization (e.g. it is [JsonIgnore]'d); thus we maintain a separate cache.
/// </summary>
public HashSet<TypeGenerationSpec> TypesWithMetadataGenerated { get; } = new();

/// <summary>
/// Cache of runtime property names (statically determined) found accross the object graph of the JsonSerializerContext.
/// </summary>
public HashSet<string> RuntimePropertyNames { get; } = new();

public string ContextTypeRef => $"global::{ContextType.GetUniqueCompilableTypeName()}";
}
}
Loading