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

Expand API documentation of contract customization APIs. #72388

Merged
merged 4 commits into from
Jul 19, 2022
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
2 changes: 1 addition & 1 deletion src/libraries/System.Text.Json/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@
<value>Runtime type '{0}' has a diamond ambiguity between derived types '{1}' and '{2}' of polymorphic type '{3}'. Consider either removing one of the derived types or removing the 'JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor' setting.</value>
</data>
<data name="InvalidJsonTypeInfoOperationForKind" xml:space="preserve">
<value>Invalid JsonTypeInfo operation for metadata kind '{0}'.</value>
<value>Invalid JsonTypeInfo operation for JsonTypeInfoKind '{0}'.</value>
</data>
<data name="CombineOneOfResolversIsNull" xml:space="preserve">
<value>One of the provided resolvers is null.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public sealed partial class JsonSerializerOptions
/// </summary>
/// <param name="type">The type to resolve contract metadata for.</param>
/// <returns>The contract metadata resolved for <paramref name="type"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="type"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="type"/> is not valid for serialization.</exception>
/// <remarks>
/// Returned metadata can be downcast to <see cref="JsonTypeInfo{T}"/> and used with the relevant <see cref="JsonSerializer"/> overloads.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,14 @@ public JsonSerializerOptions(JsonSerializerDefaults defaults) : this()
}

/// <summary>
/// Gets or sets a <see cref="JsonTypeInfo"/> contract resolver.
/// Gets or sets the <see cref="JsonTypeInfo"/> contract resolver used by this instance.
/// </summary>
/// <exception cref="InvalidOperationException">
/// Thrown if this property is set after serialization or deserialization has occurred.
/// </exception>
/// <remarks>
/// When used with the reflection-based <see cref="JsonSerializer"/> APIs,
/// a <see langword="null"/> setting be equivalent to and replaced by the reflection-based
/// <see cref="DefaultJsonTypeInfoResolver"/>.
/// A <see langword="null"/> setting is equivalent to using the reflection-based <see cref="DefaultJsonTypeInfoResolver" />.
/// The property will be populated automatically once used with one of the <see cref="JsonSerializer"/> methods.
/// </remarks>
public IJsonTypeInfoResolver? TypeInfoResolver
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Default JsonTypeInfo resolver.
/// Defines the default, reflection-based JSON contract resolver used by System.Text.Json.
/// </summary>
/// <remarks>
/// The contract resolver used by <see cref="JsonSerializerOptions.Default"/>.
/// </remarks>
public partial class DefaultJsonTypeInfoResolver : IJsonTypeInfoResolver
{
private bool _mutable;

/// <summary>
/// Constructs DefaultJsonTypeInfoResolver.
/// Creates a mutable <see cref="DefaultJsonTypeInfoResolver"/> instance.
/// </summary>
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
Expand All @@ -35,7 +38,17 @@ private DefaultJsonTypeInfoResolver(bool mutable)
s_defaultSimpleConverters ??= GetDefaultSimpleConverters();
}

/// <inheritdoc/>
/// <summary>
/// Resolves a JSON contract for a given <paramref name="type"/> and <paramref name="options"/> configuration.
/// </summary>
/// <param name="type">The type for which to resolve a JSON contract.</param>
/// <param name="options">A <see cref="JsonSerializerOptions"/> instance used to determine contract configuration.</param>
/// <returns>A <see cref="JsonTypeInfo"/> defining a reflection-derived JSON contract for <paramref name="type"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="type"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
/// <remarks>
/// The base implementation of this method will produce a reflection-derived contract
/// and apply any callbacks from the <see cref="Modifiers"/> list.
/// </remarks>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Expand Down Expand Up @@ -88,9 +101,13 @@ private static JsonTypeInfo<T> CreateReflectionJsonTypeInfo<T>(JsonSerializerOpt
private static MethodInfo? s_createReflectionJsonTypeInfoMethodInfo;

/// <summary>
/// List of JsonTypeInfo modifiers. Modifying callbacks are called consecutively after initial resolution
/// and cannot be changed after GetTypeInfo is called.
/// Gets a list of user-defined callbacks that can be used to modify the initial contract.
/// </summary>
/// <remarks>
/// The modifier list will be rendered immutable after the first <see cref="GetTypeInfo(Type, JsonSerializerOptions)"/> invocation.
///
/// Modifier callbacks are called consecutively in the order in which they are specified in the list.
/// </remarks>
public IList<Action<JsonTypeInfo>> Modifiers => _modifiers ??= new ModifierCollection(this);
private ModifierCollection? _modifiers;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Exposes method for resolving Type into JsonTypeInfo for given options.
/// Used to resolve the JSON serialization contract for requested types.
/// </summary>
public interface IJsonTypeInfoResolver
{
/// <summary>
/// Resolves Type into JsonTypeInfo which defines serialization and deserialization logic.
/// Resolves a <see cref="JsonTypeInfo"/> contract for the requested type and options.
/// </summary>
/// <param name="type">Type to be resolved.</param>
/// <param name="options">JsonSerializerOptions instance defining resolution parameters.</param>
/// <returns>Returns JsonTypeInfo instance or null if the resolver cannot produce metadata for this type.</returns>
/// <param name="options">Configuration used when resolving the metadata.</param>
/// <returns>
/// A <see cref="JsonTypeInfo"/> instance matching the requested type,
/// or <see langword="null"/> if no contract could be resolved.
/// </returns>
JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class JsonPolymorphismOptions
/// unrecognized type discriminator id's and reverts to the contract of the base type.
/// Otherwise, it will fail the deserialization.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The parent <see cref="JsonTypeInfo"/> instance has been locked for further modification.
/// </exception>
public bool IgnoreUnrecognizedTypeDiscriminators
{
get => _ignoreUnrecognizedTypeDiscriminators;
Expand All @@ -40,6 +43,9 @@ public bool IgnoreUnrecognizedTypeDiscriminators
/// <summary>
/// Gets or sets the behavior when serializing an undeclared derived runtime type.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The parent <see cref="JsonTypeInfo"/> instance has been locked for further modification.
/// </exception>
public JsonUnknownDerivedTypeHandling UnknownDerivedTypeHandling
{
get => _unknownDerivedTypeHandling;
Expand All @@ -54,6 +60,9 @@ public JsonUnknownDerivedTypeHandling UnknownDerivedTypeHandling
/// Gets or sets a custom type discriminator property name for the polymorhic type.
/// Uses the default '$type' property name if left unset.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The parent <see cref="JsonTypeInfo"/> instance has been locked for further modification.
/// </exception>
[AllowNull]
public string TypeDiscriminatorPropertyName
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace System.Text.Json.Serialization.Metadata
{
/// <summary>
/// Provides JSON serialization-related metadata about a property or field.
/// Provides JSON serialization-related metadata about a property or field defined in an object.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public abstract class JsonPropertyInfo
Expand All @@ -28,8 +28,17 @@ public abstract class JsonPropertyInfo
internal abstract JsonConverter EffectiveConverter { get; }

/// <summary>
/// Custom converter override at the property level, equivalent to <see cref="JsonConverterAttribute" /> annotation.
/// Gets or sets a custom converter override for the current property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// It is possible to use <see cref="JsonConverterFactory"/> instances with this property.
///
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/>, the value of
/// <see cref="CustomConverter"/> will be mapped from <see cref="JsonConverterAttribute" /> annotations.
/// </remarks>
public JsonConverter? CustomConverter
{
get => _customConverter;
Expand All @@ -45,6 +54,9 @@ public JsonConverter? CustomConverter
/// <summary>
/// Gets or sets a getter delegate for the property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// Setting to <see langword="null"/> will result in the property being skipped on serialization.
/// </remarks>
Expand All @@ -61,6 +73,9 @@ public JsonConverter? CustomConverter
/// <summary>
/// Gets or sets a setter delegate for the property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// Setting to <see langword="null"/> will result in the property being skipped on deserialization.
/// </remarks>
Expand All @@ -85,13 +100,16 @@ public JsonConverter? CustomConverter
/// <summary>
/// Gets or sets a predicate deciding whether the current property value should be serialized.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// The first parameter denotes the parent object, the second parameter denotes the property value.
///
/// Setting the predicate to <see langword="null"/> is equivalent to always serializing the property value.
///
/// When serializing using <see cref="DefaultJsonTypeInfoResolver"/>, the value of
/// <see cref="JsonIgnoreAttribute.Condition"/> will map to this predicate.
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/>,
/// the value of <see cref="JsonIgnoreAttribute.Condition"/> will map to this predicate.
/// </remarks>
public Func<object, object?, bool>? ShouldSerialize
{
Expand Down Expand Up @@ -127,6 +145,9 @@ internal JsonIgnoreCondition? IgnoreCondition
/// <summary>
/// Gets or sets a custom attribute provider for the current property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// When resolving metadata via <see cref="DefaultJsonTypeInfoResolver"/> this
/// will be populated with the underlying <see cref="MemberInfo" /> of the serialized property or field.
Expand All @@ -153,9 +174,16 @@ public ICustomAttributeProvider? AttributeProvider
/// <summary>
/// Specifies whether the current property is a special extension data property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
///
/// -or-
///
/// The current <see cref="PropertyType"/> is not valid for use with extension data.
/// </exception>
/// <remarks>
/// Properties annotated with <see cref="JsonExtensionDataAttribute"/>
/// will appear here when using <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>.
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
/// the value of this property will be mapped from <see cref="JsonExtensionDataAttribute"/> annotations.
/// </remarks>
public bool IsExtensionData
{
Expand All @@ -164,7 +192,7 @@ public bool IsExtensionData
{
VerifyMutable();

if (value && !JsonTypeInfo.IsValidExtensionDataProperty(this))
if (value && !JsonTypeInfo.IsValidExtensionDataProperty(PropertyType))
{
ThrowHelper.ThrowInvalidOperationException_SerializationDataExtensionPropertyInvalid(this);
}
Expand Down Expand Up @@ -199,7 +227,7 @@ internal static JsonPropertyInfo GetPropertyPlaceholder()
}

/// <summary>
/// Gets the type of the current property metadata.
/// Gets the type of the current property.
/// </summary>
public Type PropertyType { get; }

Expand Down Expand Up @@ -537,16 +565,22 @@ internal bool IgnoreReadOnlyMember

// There are 3 copies of the property name:
// 1) Name. The unescaped property name.
// 2) NameAsUtf8Bytes. The Utf8 version of Name. Used during during deserialization for property lookup.
// 2) NameAsUtf8Bytes. The Utf8 version of Name. Used during deserialization for property lookup.
// 3) EscapedNameSection. The escaped version of NameAsUtf8Bytes plus the wrapping quotes and a trailing colon. Used during serialization.

/// <summary>
/// Gets or sets the JSON property name used when serializing the property.
/// </summary>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is null.</exception>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// This typically reflects the underlying .NET member name,
/// the name derived from <see cref="JsonSerializerOptions.PropertyNamingPolicy" />,
/// or the value specified in <see cref="JsonPropertyNameAttribute" />,
/// The value of <see cref="Name"/> cannot conflict with that of other <see cref="JsonPropertyInfo"/> defined in the declaring <see cref="JsonTypeInfo"/>.
///
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
/// the value typically reflects the underlying .NET member name, the name derived from <see cref="JsonSerializerOptions.PropertyNamingPolicy" />,
/// or the value specified in <see cref="JsonPropertyNameAttribute" />.
/// </remarks>
public string Name
{
Expand Down Expand Up @@ -581,16 +615,19 @@ public string Name
internal byte[] EscapedNameSection { get; set; } = null!;

/// <summary>
/// Options associated with JsonPropertyInfo
/// Gets the <see cref="JsonSerializerOptions"/> value associated with the current contract instance.
/// </summary>
public JsonSerializerOptions Options { get; }

/// <summary>
/// Gets or sets the serialization order for the current property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// When using <see cref="DefaultJsonTypeInfoResolver"/>, properties annotated
/// with the <see cref="JsonPropertyOrderAttribute"/> will map to this value.
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
/// the value of this property will be mapped from <see cref="JsonPropertyOrderAttribute"/> annotations.
/// </remarks>
public int Order
{
Expand Down Expand Up @@ -752,8 +789,15 @@ internal JsonTypeInfo JsonTypeInfo
internal JsonNumberHandling? DeclaringTypeNumberHandling { get; set; }

/// <summary>
/// Number handling specific to this property, i.e. set by attribute
/// Gets or sets the <see cref="JsonNumberHandling"/> applied to the current property.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The <see cref="JsonPropertyInfo"/> instance has been locked for further modification.
/// </exception>
/// <remarks>
/// For contracts originating from <see cref="DefaultJsonTypeInfoResolver"/> or <see cref="JsonSerializerContext"/>,
/// the value of this property will be mapped from <see cref="JsonNumberHandlingAttribute"/> annotations.
/// </remarks>
public JsonNumberHandling? NumberHandling
{
get => _numberHandling;
Expand Down
Loading