| File: System\Text\Json\Serialization\JsonSerializer.Read.String.cs | Web Access |
| Project: src\runtime\src\libraries\System.Text.Json\src\System.Text.Json.csproj (System.Text.Json) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { /// <summary> /// Provides functionality to serialize objects or value types to JSON and /// deserialize JSON into objects or value types. /// </summary> public static partial class JsonSerializer { /// <summary> /// Parses the text representing a single JSON value into a <typeparamref name="TValue"/>. /// </summary> /// <typeparam name="TValue">The type to deserialize the JSON value into.</typeparam> /// <returns>A <typeparamref name="TValue"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="options">Options to control the behavior during parsing.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <typeparamref name="TValue" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <typeparamref name="TValue"/> or its serializable members. /// </exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] public static TValue? Deserialize<TValue>([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonSerializerOptions? options = null) { ArgumentNullException.ThrowIfNull(json); JsonTypeInfo<TValue> jsonTypeInfo = GetTypeInfo<TValue>(options); return ReadFromSpan(json.AsSpan(), jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into an instance of the type specified by a generic type parameter. /// </summary> /// <typeparam name="TValue">The type to deserialize the JSON value into.</typeparam> /// <returns>A <typeparamref name="TValue"/> representation of the JSON value.</returns> /// <param name="json">The JSON text to parse.</param> /// <param name="options">Options to control the behavior during parsing.</param> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <typeparamref name="TValue" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the span beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <typeparamref name="TValue"/> or its serializable members. /// </exception> /// <remarks>Using a UTF-16 span is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] public static TValue? Deserialize<TValue>([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, JsonSerializerOptions? options = null) { JsonTypeInfo<TValue> jsonTypeInfo = GetTypeInfo<TValue>(options); return ReadFromSpan(json, jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into a <paramref name="returnType"/>. /// </summary> /// <returns>A <paramref name="returnType"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="returnType">The type of the object to convert to and return.</param> /// <param name="options">Options to control the behavior during parsing.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> or <paramref name="returnType"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <paramref name="returnType"/> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <paramref name="returnType"/> or its serializable members. /// </exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, Type returnType, JsonSerializerOptions? options = null) { ArgumentNullException.ThrowIfNull(json); ArgumentNullException.ThrowIfNull(returnType); JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); return ReadFromSpanAsObject(json.AsSpan(), jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into an instance of a specified type. /// </summary> /// <returns>A <paramref name="returnType"/> representation of the JSON value.</returns> /// <param name="json">The JSON text to parse.</param> /// <param name="returnType">The type of the object to convert to and return.</param> /// <param name="options">Options to control the behavior during parsing.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="returnType"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <paramref name="returnType"/> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the span beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <paramref name="returnType"/> or its serializable members. /// </exception> /// <remarks>Using a UTF-16 span is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, Type returnType, JsonSerializerOptions? options = null) { ArgumentNullException.ThrowIfNull(returnType); // default/null span is treated as empty JsonTypeInfo jsonTypeInfo = GetTypeInfo(options, returnType); return ReadFromSpanAsObject(json, jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into a <typeparamref name="TValue"/>. /// </summary> /// <typeparam name="TValue">The type to deserialize the JSON value into.</typeparam> /// <returns>A <typeparamref name="TValue"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> is <see langword="null"/>. /// /// -or- /// /// <paramref name="jsonTypeInfo"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <typeparamref name="TValue" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static TValue? Deserialize<TValue>([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonTypeInfo<TValue> jsonTypeInfo) { ArgumentNullException.ThrowIfNull(json); ArgumentNullException.ThrowIfNull(jsonTypeInfo); jsonTypeInfo.EnsureConfigured(); return ReadFromSpan(json.AsSpan(), jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into a <typeparamref name="TValue"/>. /// </summary> /// <typeparam name="TValue">The type to deserialize the JSON value into.</typeparam> /// <returns>A <typeparamref name="TValue"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> is <see langword="null"/>. /// /// -or- /// /// <paramref name="jsonTypeInfo"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <typeparamref name="TValue" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static TValue? Deserialize<TValue>([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, JsonTypeInfo<TValue> jsonTypeInfo) { ArgumentNullException.ThrowIfNull(jsonTypeInfo); jsonTypeInfo.EnsureConfigured(); return ReadFromSpan(json, jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into an instance specified by the <paramref name="jsonTypeInfo"/>. /// </summary> /// <returns>A <paramref name="jsonTypeInfo"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> is <see langword="null"/>. /// /// -or- /// /// <paramref name="jsonTypeInfo"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, JsonTypeInfo jsonTypeInfo) { ArgumentNullException.ThrowIfNull(json); ArgumentNullException.ThrowIfNull(jsonTypeInfo); jsonTypeInfo.EnsureConfigured(); return ReadFromSpanAsObject(json.AsSpan(), jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into an instance specified by the <paramref name="jsonTypeInfo"/>. /// </summary> /// <returns>A <paramref name="jsonTypeInfo"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="jsonTypeInfo">Metadata about the type to convert.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="jsonTypeInfo"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, JsonTypeInfo jsonTypeInfo) { ArgumentNullException.ThrowIfNull(jsonTypeInfo); jsonTypeInfo.EnsureConfigured(); return ReadFromSpanAsObject(json, jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into a <paramref name="returnType"/>. /// </summary> /// <returns>A <paramref name="returnType"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="returnType">The type of the object to convert to and return.</param> /// <param name="context">A metadata provider for serializable types.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> or <paramref name="returnType"/> is <see langword="null"/>. /// /// -or- /// /// <paramref name="context"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <paramref name="returnType" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <paramref name="returnType"/> or its serializable members. /// </exception> /// <exception cref="InvalidOperationException"> /// The <see cref="JsonSerializerContext.GetTypeInfo(Type)"/> method of the provided /// <paramref name="context"/> returns <see langword="null"/> for the type to convert. /// </exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] string json, Type returnType, JsonSerializerContext context) { ArgumentNullException.ThrowIfNull(json); ArgumentNullException.ThrowIfNull(returnType); ArgumentNullException.ThrowIfNull(context); JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); return ReadFromSpanAsObject(json.AsSpan(), jsonTypeInfo); } /// <summary> /// Parses the text representing a single JSON value into a <paramref name="returnType"/>. /// </summary> /// <returns>A <paramref name="returnType"/> representation of the JSON value.</returns> /// <param name="json">JSON text to parse.</param> /// <param name="returnType">The type of the object to convert to and return.</param> /// <param name="context">A metadata provider for serializable types.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="json"/> or <paramref name="returnType"/> is <see langword="null"/>. /// /// -or- /// /// <paramref name="context"/> is <see langword="null"/>. /// </exception> /// <exception cref="JsonException"> /// The JSON is invalid. /// /// -or- /// /// <paramref name="returnType" /> is not compatible with the JSON. /// /// -or- /// /// There is remaining data in the string beyond a single JSON value.</exception> /// <exception cref="NotSupportedException"> /// There is no compatible <see cref="System.Text.Json.Serialization.JsonConverter"/> /// for <paramref name="returnType"/> or its serializable members. /// </exception> /// <exception cref="InvalidOperationException"> /// The <see cref="JsonSerializerContext.GetTypeInfo(Type)"/> method of the provided /// <paramref name="context"/> returns <see langword="null"/> for the type to convert. /// </exception> /// <remarks>Using a <see cref="string"/> is not as efficient as using the /// UTF-8 methods since the implementation natively uses UTF-8. /// </remarks> public static object? Deserialize([StringSyntax(StringSyntaxAttribute.Json)] ReadOnlySpan<char> json, Type returnType, JsonSerializerContext context) { ArgumentNullException.ThrowIfNull(returnType); ArgumentNullException.ThrowIfNull(context); JsonTypeInfo jsonTypeInfo = GetTypeInfo(context, returnType); return ReadFromSpanAsObject(json, jsonTypeInfo); } private static unsafe TValue? ReadFromSpan<TValue>(ReadOnlySpan<char> json, JsonTypeInfo<TValue> jsonTypeInfo) { Debug.Assert(jsonTypeInfo.IsConfigured); byte[]? tempArray = null; // For performance, avoid obtaining actual byte count unless memory usage is higher than the threshold. Span<byte> utf8 = // Use stack memory json.Length <= (JsonConstants.StackallocByteThreshold / JsonConstants.MaxExpansionFactorWhileTranscoding) ? stackalloc byte[JsonConstants.StackallocByteThreshold] : // Use a pooled array json.Length <= (JsonConstants.ArrayPoolMaxSizeBeforeUsingNormalAlloc / JsonConstants.MaxExpansionFactorWhileTranscoding) ? tempArray = ArrayPool<byte>.Shared.Rent(json.Length * JsonConstants.MaxExpansionFactorWhileTranscoding) : // Use a normal alloc since the pool would create a normal alloc anyway based on the threshold (per current implementation) // and by using a normal alloc we can avoid the Clear(). new byte[JsonReaderHelper.GetUtf8ByteCount(json)]; try { int actualByteCount = JsonReaderHelper.GetUtf8FromText(json, utf8); utf8 = utf8.Slice(0, actualByteCount); return ReadFromSpan(utf8, jsonTypeInfo, actualByteCount); } finally { if (tempArray != null) { utf8.Clear(); ArrayPool<byte>.Shared.Return(tempArray); } } } private static unsafe object? ReadFromSpanAsObject(ReadOnlySpan<char> json, JsonTypeInfo jsonTypeInfo) { Debug.Assert(jsonTypeInfo.IsConfigured); byte[]? tempArray = null; // For performance, avoid obtaining actual byte count unless memory usage is higher than the threshold. Span<byte> utf8 = // Use stack memory json.Length <= (JsonConstants.StackallocByteThreshold / JsonConstants.MaxExpansionFactorWhileTranscoding) ? stackalloc byte[JsonConstants.StackallocByteThreshold] : // Use a pooled array json.Length <= (JsonConstants.ArrayPoolMaxSizeBeforeUsingNormalAlloc / JsonConstants.MaxExpansionFactorWhileTranscoding) ? tempArray = ArrayPool<byte>.Shared.Rent(json.Length * JsonConstants.MaxExpansionFactorWhileTranscoding) : // Use a normal alloc since the pool would create a normal alloc anyway based on the threshold (per current implementation) // and by using a normal alloc we can avoid the Clear(). new byte[JsonReaderHelper.GetUtf8ByteCount(json)]; try { int actualByteCount = JsonReaderHelper.GetUtf8FromText(json, utf8); utf8 = utf8.Slice(0, actualByteCount); return ReadFromSpanAsObject(utf8, jsonTypeInfo, actualByteCount); } finally { if (tempArray != null) { utf8.Clear(); ArrayPool<byte>.Shared.Return(tempArray); } } } } }