1227 lines
50 KiB
C#
1227 lines
50 KiB
C#
|
#region License
|
||
|
// Copyright (c) 2007 James Newton-King
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person
|
||
|
// obtaining a copy of this software and associated documentation
|
||
|
// files (the "Software"), to deal in the Software without
|
||
|
// restriction, including without limitation the rights to use,
|
||
|
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
// copies of the Software, and to permit persons to whom the
|
||
|
// Software is furnished to do so, subject to the following
|
||
|
// conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be
|
||
|
// included in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
// OTHER DEALINGS IN THE SOFTWARE.
|
||
|
#endregion
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.IO;
|
||
|
using System.Runtime.Serialization.Formatters;
|
||
|
using LC.Newtonsoft.Json.Converters;
|
||
|
using LC.Newtonsoft.Json.Serialization;
|
||
|
using LC.Newtonsoft.Json.Utilities;
|
||
|
using System.Runtime.Serialization;
|
||
|
using ErrorEventArgs = LC.Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||
|
using System.Runtime.CompilerServices;
|
||
|
using System.Diagnostics.CodeAnalysis;
|
||
|
|
||
|
namespace LC.Newtonsoft.Json
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Serializes and deserializes objects into and from the JSON format.
|
||
|
/// The <see cref="JsonSerializer"/> enables you to control how objects are encoded into JSON.
|
||
|
/// </summary>
|
||
|
public class JsonSerializer
|
||
|
{
|
||
|
internal TypeNameHandling _typeNameHandling;
|
||
|
internal TypeNameAssemblyFormatHandling _typeNameAssemblyFormatHandling;
|
||
|
internal PreserveReferencesHandling _preserveReferencesHandling;
|
||
|
internal ReferenceLoopHandling _referenceLoopHandling;
|
||
|
internal MissingMemberHandling _missingMemberHandling;
|
||
|
internal ObjectCreationHandling _objectCreationHandling;
|
||
|
internal NullValueHandling _nullValueHandling;
|
||
|
internal DefaultValueHandling _defaultValueHandling;
|
||
|
internal ConstructorHandling _constructorHandling;
|
||
|
internal MetadataPropertyHandling _metadataPropertyHandling;
|
||
|
internal JsonConverterCollection? _converters;
|
||
|
internal IContractResolver _contractResolver;
|
||
|
internal ITraceWriter? _traceWriter;
|
||
|
internal IEqualityComparer? _equalityComparer;
|
||
|
internal ISerializationBinder _serializationBinder;
|
||
|
internal StreamingContext _context;
|
||
|
private IReferenceResolver? _referenceResolver;
|
||
|
|
||
|
private Formatting? _formatting;
|
||
|
private DateFormatHandling? _dateFormatHandling;
|
||
|
private DateTimeZoneHandling? _dateTimeZoneHandling;
|
||
|
private DateParseHandling? _dateParseHandling;
|
||
|
private FloatFormatHandling? _floatFormatHandling;
|
||
|
private FloatParseHandling? _floatParseHandling;
|
||
|
private StringEscapeHandling? _stringEscapeHandling;
|
||
|
private CultureInfo _culture;
|
||
|
private int? _maxDepth;
|
||
|
private bool _maxDepthSet;
|
||
|
private bool? _checkAdditionalContent;
|
||
|
private string? _dateFormatString;
|
||
|
private bool _dateFormatStringSet;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Occurs when the <see cref="JsonSerializer"/> errors during serialization and deserialization.
|
||
|
/// </summary>
|
||
|
public virtual event EventHandler<ErrorEventArgs>? Error;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
|
||
|
/// </summary>
|
||
|
public virtual IReferenceResolver? ReferenceResolver
|
||
|
{
|
||
|
get => GetReferenceResolver();
|
||
|
set
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
throw new ArgumentNullException(nameof(value), "Reference resolver cannot be null.");
|
||
|
}
|
||
|
|
||
|
_referenceResolver = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the <see cref="SerializationBinder"/> used by the serializer when resolving type names.
|
||
|
/// </summary>
|
||
|
[Obsolete("Binder is obsolete. Use SerializationBinder instead.")]
|
||
|
public virtual SerializationBinder Binder
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (_serializationBinder is SerializationBinder legacySerializationBinder)
|
||
|
{
|
||
|
return legacySerializationBinder;
|
||
|
}
|
||
|
|
||
|
if (_serializationBinder is SerializationBinderAdapter adapter)
|
||
|
{
|
||
|
return adapter.SerializationBinder;
|
||
|
}
|
||
|
|
||
|
throw new InvalidOperationException("Cannot get SerializationBinder because an ISerializationBinder was previously set.");
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null.");
|
||
|
}
|
||
|
|
||
|
_serializationBinder = value as ISerializationBinder ?? new SerializationBinderAdapter(value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the <see cref="ISerializationBinder"/> used by the serializer when resolving type names.
|
||
|
/// </summary>
|
||
|
public virtual ISerializationBinder SerializationBinder
|
||
|
{
|
||
|
get => _serializationBinder;
|
||
|
set
|
||
|
{
|
||
|
if (value == null)
|
||
|
{
|
||
|
throw new ArgumentNullException(nameof(value), "Serialization binder cannot be null.");
|
||
|
}
|
||
|
|
||
|
_serializationBinder = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the <see cref="ITraceWriter"/> used by the serializer when writing trace messages.
|
||
|
/// </summary>
|
||
|
/// <value>The trace writer.</value>
|
||
|
public virtual ITraceWriter? TraceWriter
|
||
|
{
|
||
|
get => _traceWriter;
|
||
|
set => _traceWriter = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the equality comparer used by the serializer when comparing references.
|
||
|
/// </summary>
|
||
|
/// <value>The equality comparer.</value>
|
||
|
public virtual IEqualityComparer? EqualityComparer
|
||
|
{
|
||
|
get => _equalityComparer;
|
||
|
set => _equalityComparer = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how type name writing and reading is handled by the serializer.
|
||
|
/// The default value is <see cref="Json.TypeNameHandling.None" />.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// <see cref="JsonSerializer.TypeNameHandling"/> should be used with caution when your application deserializes JSON from an external source.
|
||
|
/// Incoming types should be validated with a custom <see cref="JsonSerializer.SerializationBinder"/>
|
||
|
/// when deserializing with a value other than <see cref="TypeNameHandling.None"/>.
|
||
|
/// </remarks>
|
||
|
public virtual TypeNameHandling TypeNameHandling
|
||
|
{
|
||
|
get => _typeNameHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < TypeNameHandling.None || value > TypeNameHandling.Auto)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_typeNameHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how a type name assembly is written and resolved by the serializer.
|
||
|
/// The default value is <see cref="FormatterAssemblyStyle.Simple" />.
|
||
|
/// </summary>
|
||
|
/// <value>The type name assembly format.</value>
|
||
|
[Obsolete("TypeNameAssemblyFormat is obsolete. Use TypeNameAssemblyFormatHandling instead.")]
|
||
|
public virtual FormatterAssemblyStyle TypeNameAssemblyFormat
|
||
|
{
|
||
|
get => (FormatterAssemblyStyle)_typeNameAssemblyFormatHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < FormatterAssemblyStyle.Simple || value > FormatterAssemblyStyle.Full)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_typeNameAssemblyFormatHandling = (TypeNameAssemblyFormatHandling)value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how a type name assembly is written and resolved by the serializer.
|
||
|
/// The default value is <see cref="Json.TypeNameAssemblyFormatHandling.Simple" />.
|
||
|
/// </summary>
|
||
|
/// <value>The type name assembly format.</value>
|
||
|
public virtual TypeNameAssemblyFormatHandling TypeNameAssemblyFormatHandling
|
||
|
{
|
||
|
get => _typeNameAssemblyFormatHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < TypeNameAssemblyFormatHandling.Simple || value > TypeNameAssemblyFormatHandling.Full)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_typeNameAssemblyFormatHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how object references are preserved by the serializer.
|
||
|
/// The default value is <see cref="Json.PreserveReferencesHandling.None" />.
|
||
|
/// </summary>
|
||
|
public virtual PreserveReferencesHandling PreserveReferencesHandling
|
||
|
{
|
||
|
get => _preserveReferencesHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < PreserveReferencesHandling.None || value > PreserveReferencesHandling.All)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_preserveReferencesHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
|
||
|
/// The default value is <see cref="Json.ReferenceLoopHandling.Error" />.
|
||
|
/// </summary>
|
||
|
public virtual ReferenceLoopHandling ReferenceLoopHandling
|
||
|
{
|
||
|
get => _referenceLoopHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_referenceLoopHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization.
|
||
|
/// The default value is <see cref="Json.MissingMemberHandling.Ignore" />.
|
||
|
/// </summary>
|
||
|
public virtual MissingMemberHandling MissingMemberHandling
|
||
|
{
|
||
|
get => _missingMemberHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < MissingMemberHandling.Ignore || value > MissingMemberHandling.Error)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_missingMemberHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how null values are handled during serialization and deserialization.
|
||
|
/// The default value is <see cref="Json.NullValueHandling.Include" />.
|
||
|
/// </summary>
|
||
|
public virtual NullValueHandling NullValueHandling
|
||
|
{
|
||
|
get => _nullValueHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < NullValueHandling.Include || value > NullValueHandling.Ignore)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_nullValueHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how default values are handled during serialization and deserialization.
|
||
|
/// The default value is <see cref="Json.DefaultValueHandling.Include" />.
|
||
|
/// </summary>
|
||
|
public virtual DefaultValueHandling DefaultValueHandling
|
||
|
{
|
||
|
get => _defaultValueHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < DefaultValueHandling.Include || value > DefaultValueHandling.IgnoreAndPopulate)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_defaultValueHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how objects are created during deserialization.
|
||
|
/// The default value is <see cref="Json.ObjectCreationHandling.Auto" />.
|
||
|
/// </summary>
|
||
|
/// <value>The object creation handling.</value>
|
||
|
public virtual ObjectCreationHandling ObjectCreationHandling
|
||
|
{
|
||
|
get => _objectCreationHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < ObjectCreationHandling.Auto || value > ObjectCreationHandling.Replace)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_objectCreationHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how constructors are used during deserialization.
|
||
|
/// The default value is <see cref="Json.ConstructorHandling.Default" />.
|
||
|
/// </summary>
|
||
|
/// <value>The constructor handling.</value>
|
||
|
public virtual ConstructorHandling ConstructorHandling
|
||
|
{
|
||
|
get => _constructorHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < ConstructorHandling.Default || value > ConstructorHandling.AllowNonPublicDefaultConstructor)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_constructorHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how metadata properties are used during deserialization.
|
||
|
/// The default value is <see cref="Json.MetadataPropertyHandling.Default" />.
|
||
|
/// </summary>
|
||
|
/// <value>The metadata properties handling.</value>
|
||
|
public virtual MetadataPropertyHandling MetadataPropertyHandling
|
||
|
{
|
||
|
get => _metadataPropertyHandling;
|
||
|
set
|
||
|
{
|
||
|
if (value < MetadataPropertyHandling.Default || value > MetadataPropertyHandling.Ignore)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||
|
}
|
||
|
|
||
|
_metadataPropertyHandling = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a collection <see cref="JsonConverter"/> that will be used during serialization.
|
||
|
/// </summary>
|
||
|
/// <value>Collection <see cref="JsonConverter"/> that will be used during serialization.</value>
|
||
|
public virtual JsonConverterCollection Converters
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (_converters == null)
|
||
|
{
|
||
|
_converters = new JsonConverterCollection();
|
||
|
}
|
||
|
|
||
|
return _converters;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the contract resolver used by the serializer when
|
||
|
/// serializing .NET objects to JSON and vice versa.
|
||
|
/// </summary>
|
||
|
public virtual IContractResolver ContractResolver
|
||
|
{
|
||
|
get => _contractResolver;
|
||
|
set => _contractResolver = value ?? DefaultContractResolver.Instance;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the <see cref="StreamingContext"/> used by the serializer when invoking serialization callback methods.
|
||
|
/// </summary>
|
||
|
/// <value>The context.</value>
|
||
|
public virtual StreamingContext Context
|
||
|
{
|
||
|
get => _context;
|
||
|
set => _context = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates how JSON text output is formatted.
|
||
|
/// The default value is <see cref="Json.Formatting.None" />.
|
||
|
/// </summary>
|
||
|
public virtual Formatting Formatting
|
||
|
{
|
||
|
get => _formatting ?? JsonSerializerSettings.DefaultFormatting;
|
||
|
set => _formatting = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how dates are written to JSON text.
|
||
|
/// The default value is <see cref="Json.DateFormatHandling.IsoDateFormat" />.
|
||
|
/// </summary>
|
||
|
public virtual DateFormatHandling DateFormatHandling
|
||
|
{
|
||
|
get => _dateFormatHandling ?? JsonSerializerSettings.DefaultDateFormatHandling;
|
||
|
set => _dateFormatHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how <see cref="DateTime"/> time zones are handled during serialization and deserialization.
|
||
|
/// The default value is <see cref="Json.DateTimeZoneHandling.RoundtripKind" />.
|
||
|
/// </summary>
|
||
|
public virtual DateTimeZoneHandling DateTimeZoneHandling
|
||
|
{
|
||
|
get => _dateTimeZoneHandling ?? JsonSerializerSettings.DefaultDateTimeZoneHandling;
|
||
|
set => _dateTimeZoneHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how date formatted strings, e.g. <c>"\/Date(1198908717056)\/"</c> and <c>"2012-03-21T05:40Z"</c>, are parsed when reading JSON.
|
||
|
/// The default value is <see cref="Json.DateParseHandling.DateTime" />.
|
||
|
/// </summary>
|
||
|
public virtual DateParseHandling DateParseHandling
|
||
|
{
|
||
|
get => _dateParseHandling ?? JsonSerializerSettings.DefaultDateParseHandling;
|
||
|
set => _dateParseHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how floating point numbers, e.g. 1.0 and 9.9, are parsed when reading JSON text.
|
||
|
/// The default value is <see cref="Json.FloatParseHandling.Double" />.
|
||
|
/// </summary>
|
||
|
public virtual FloatParseHandling FloatParseHandling
|
||
|
{
|
||
|
get => _floatParseHandling ?? JsonSerializerSettings.DefaultFloatParseHandling;
|
||
|
set => _floatParseHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how special floating point numbers, e.g. <see cref="Double.NaN"/>,
|
||
|
/// <see cref="Double.PositiveInfinity"/> and <see cref="Double.NegativeInfinity"/>,
|
||
|
/// are written as JSON text.
|
||
|
/// The default value is <see cref="Json.FloatFormatHandling.String" />.
|
||
|
/// </summary>
|
||
|
public virtual FloatFormatHandling FloatFormatHandling
|
||
|
{
|
||
|
get => _floatFormatHandling ?? JsonSerializerSettings.DefaultFloatFormatHandling;
|
||
|
set => _floatFormatHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how strings are escaped when writing JSON text.
|
||
|
/// The default value is <see cref="Json.StringEscapeHandling.Default" />.
|
||
|
/// </summary>
|
||
|
public virtual StringEscapeHandling StringEscapeHandling
|
||
|
{
|
||
|
get => _stringEscapeHandling ?? JsonSerializerSettings.DefaultStringEscapeHandling;
|
||
|
set => _stringEscapeHandling = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets how <see cref="DateTime"/> and <see cref="DateTimeOffset"/> values are formatted when writing JSON text,
|
||
|
/// and the expected date format when reading JSON text.
|
||
|
/// The default value is <c>"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"</c>.
|
||
|
/// </summary>
|
||
|
public virtual string DateFormatString
|
||
|
{
|
||
|
get => _dateFormatString ?? JsonSerializerSettings.DefaultDateFormatString;
|
||
|
set
|
||
|
{
|
||
|
_dateFormatString = value;
|
||
|
_dateFormatStringSet = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the culture used when reading JSON.
|
||
|
/// The default value is <see cref="CultureInfo.InvariantCulture"/>.
|
||
|
/// </summary>
|
||
|
public virtual CultureInfo Culture
|
||
|
{
|
||
|
get => _culture ?? JsonSerializerSettings.DefaultCulture;
|
||
|
set => _culture = value;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
|
||
|
/// A null value means there is no maximum.
|
||
|
/// The default value is <c>128</c>.
|
||
|
/// </summary>
|
||
|
public virtual int? MaxDepth
|
||
|
{
|
||
|
get => _maxDepth;
|
||
|
set
|
||
|
{
|
||
|
if (value <= 0)
|
||
|
{
|
||
|
throw new ArgumentException("Value must be positive.", nameof(value));
|
||
|
}
|
||
|
|
||
|
_maxDepth = value;
|
||
|
_maxDepthSet = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a value indicating whether there will be a check for additional JSON content after deserializing an object.
|
||
|
/// The default value is <c>false</c>.
|
||
|
/// </summary>
|
||
|
/// <value>
|
||
|
/// <c>true</c> if there will be a check for additional JSON content after deserializing an object; otherwise, <c>false</c>.
|
||
|
/// </value>
|
||
|
public virtual bool CheckAdditionalContent
|
||
|
{
|
||
|
get => _checkAdditionalContent ?? JsonSerializerSettings.DefaultCheckAdditionalContent;
|
||
|
set => _checkAdditionalContent = value;
|
||
|
}
|
||
|
|
||
|
internal bool IsCheckAdditionalContentSet()
|
||
|
{
|
||
|
return (_checkAdditionalContent != null);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the <see cref="JsonSerializer"/> class.
|
||
|
/// </summary>
|
||
|
public JsonSerializer()
|
||
|
{
|
||
|
_referenceLoopHandling = JsonSerializerSettings.DefaultReferenceLoopHandling;
|
||
|
_missingMemberHandling = JsonSerializerSettings.DefaultMissingMemberHandling;
|
||
|
_nullValueHandling = JsonSerializerSettings.DefaultNullValueHandling;
|
||
|
_defaultValueHandling = JsonSerializerSettings.DefaultDefaultValueHandling;
|
||
|
_objectCreationHandling = JsonSerializerSettings.DefaultObjectCreationHandling;
|
||
|
_preserveReferencesHandling = JsonSerializerSettings.DefaultPreserveReferencesHandling;
|
||
|
_constructorHandling = JsonSerializerSettings.DefaultConstructorHandling;
|
||
|
_typeNameHandling = JsonSerializerSettings.DefaultTypeNameHandling;
|
||
|
_metadataPropertyHandling = JsonSerializerSettings.DefaultMetadataPropertyHandling;
|
||
|
_context = JsonSerializerSettings.DefaultContext;
|
||
|
_serializationBinder = DefaultSerializationBinder.Instance;
|
||
|
|
||
|
_culture = JsonSerializerSettings.DefaultCulture;
|
||
|
_contractResolver = DefaultContractResolver.Instance;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new <see cref="JsonSerializer"/> instance.
|
||
|
/// The <see cref="JsonSerializer"/> will not use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </summary>
|
||
|
/// <returns>
|
||
|
/// A new <see cref="JsonSerializer"/> instance.
|
||
|
/// The <see cref="JsonSerializer"/> will not use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </returns>
|
||
|
public static JsonSerializer Create()
|
||
|
{
|
||
|
return new JsonSerializer();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// The <see cref="JsonSerializer"/> will not use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="settings">The settings to be applied to the <see cref="JsonSerializer"/>.</param>
|
||
|
/// <returns>
|
||
|
/// A new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// The <see cref="JsonSerializer"/> will not use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </returns>
|
||
|
public static JsonSerializer Create(JsonSerializerSettings? settings)
|
||
|
{
|
||
|
JsonSerializer serializer = Create();
|
||
|
|
||
|
if (settings != null)
|
||
|
{
|
||
|
ApplySerializerSettings(serializer, settings);
|
||
|
}
|
||
|
|
||
|
return serializer;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new <see cref="JsonSerializer"/> instance.
|
||
|
/// The <see cref="JsonSerializer"/> will use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </summary>
|
||
|
/// <returns>
|
||
|
/// A new <see cref="JsonSerializer"/> instance.
|
||
|
/// The <see cref="JsonSerializer"/> will use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/>.
|
||
|
/// </returns>
|
||
|
public static JsonSerializer CreateDefault()
|
||
|
{
|
||
|
// copy static to local variable to avoid concurrency issues
|
||
|
JsonSerializerSettings? defaultSettings = JsonConvert.DefaultSettings?.Invoke();
|
||
|
|
||
|
return Create(defaultSettings);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// The <see cref="JsonSerializer"/> will use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/> as well as the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="settings">The settings to be applied to the <see cref="JsonSerializer"/>.</param>
|
||
|
/// <returns>
|
||
|
/// A new <see cref="JsonSerializer"/> instance using the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// The <see cref="JsonSerializer"/> will use default settings
|
||
|
/// from <see cref="JsonConvert.DefaultSettings"/> as well as the specified <see cref="JsonSerializerSettings"/>.
|
||
|
/// </returns>
|
||
|
public static JsonSerializer CreateDefault(JsonSerializerSettings? settings)
|
||
|
{
|
||
|
JsonSerializer serializer = CreateDefault();
|
||
|
if (settings != null)
|
||
|
{
|
||
|
ApplySerializerSettings(serializer, settings);
|
||
|
}
|
||
|
|
||
|
return serializer;
|
||
|
}
|
||
|
|
||
|
private static void ApplySerializerSettings(JsonSerializer serializer, JsonSerializerSettings settings)
|
||
|
{
|
||
|
if (!CollectionUtils.IsNullOrEmpty(settings.Converters))
|
||
|
{
|
||
|
// insert settings converters at the beginning so they take precedence
|
||
|
// if user wants to remove one of the default converters they will have to do it manually
|
||
|
for (int i = 0; i < settings.Converters.Count; i++)
|
||
|
{
|
||
|
serializer.Converters.Insert(i, settings.Converters[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// serializer specific
|
||
|
if (settings._typeNameHandling != null)
|
||
|
{
|
||
|
serializer.TypeNameHandling = settings.TypeNameHandling;
|
||
|
}
|
||
|
if (settings._metadataPropertyHandling != null)
|
||
|
{
|
||
|
serializer.MetadataPropertyHandling = settings.MetadataPropertyHandling;
|
||
|
}
|
||
|
if (settings._typeNameAssemblyFormatHandling != null)
|
||
|
{
|
||
|
serializer.TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling;
|
||
|
}
|
||
|
if (settings._preserveReferencesHandling != null)
|
||
|
{
|
||
|
serializer.PreserveReferencesHandling = settings.PreserveReferencesHandling;
|
||
|
}
|
||
|
if (settings._referenceLoopHandling != null)
|
||
|
{
|
||
|
serializer.ReferenceLoopHandling = settings.ReferenceLoopHandling;
|
||
|
}
|
||
|
if (settings._missingMemberHandling != null)
|
||
|
{
|
||
|
serializer.MissingMemberHandling = settings.MissingMemberHandling;
|
||
|
}
|
||
|
if (settings._objectCreationHandling != null)
|
||
|
{
|
||
|
serializer.ObjectCreationHandling = settings.ObjectCreationHandling;
|
||
|
}
|
||
|
if (settings._nullValueHandling != null)
|
||
|
{
|
||
|
serializer.NullValueHandling = settings.NullValueHandling;
|
||
|
}
|
||
|
if (settings._defaultValueHandling != null)
|
||
|
{
|
||
|
serializer.DefaultValueHandling = settings.DefaultValueHandling;
|
||
|
}
|
||
|
if (settings._constructorHandling != null)
|
||
|
{
|
||
|
serializer.ConstructorHandling = settings.ConstructorHandling;
|
||
|
}
|
||
|
if (settings._context != null)
|
||
|
{
|
||
|
serializer.Context = settings.Context;
|
||
|
}
|
||
|
if (settings._checkAdditionalContent != null)
|
||
|
{
|
||
|
serializer._checkAdditionalContent = settings._checkAdditionalContent;
|
||
|
}
|
||
|
|
||
|
if (settings.Error != null)
|
||
|
{
|
||
|
serializer.Error += settings.Error;
|
||
|
}
|
||
|
|
||
|
if (settings.ContractResolver != null)
|
||
|
{
|
||
|
serializer.ContractResolver = settings.ContractResolver;
|
||
|
}
|
||
|
if (settings.ReferenceResolverProvider != null)
|
||
|
{
|
||
|
serializer.ReferenceResolver = settings.ReferenceResolverProvider();
|
||
|
}
|
||
|
if (settings.TraceWriter != null)
|
||
|
{
|
||
|
serializer.TraceWriter = settings.TraceWriter;
|
||
|
}
|
||
|
if (settings.EqualityComparer != null)
|
||
|
{
|
||
|
serializer.EqualityComparer = settings.EqualityComparer;
|
||
|
}
|
||
|
if (settings.SerializationBinder != null)
|
||
|
{
|
||
|
serializer.SerializationBinder = settings.SerializationBinder;
|
||
|
}
|
||
|
|
||
|
// reader/writer specific
|
||
|
// unset values won't override reader/writer set values
|
||
|
if (settings._formatting != null)
|
||
|
{
|
||
|
serializer._formatting = settings._formatting;
|
||
|
}
|
||
|
if (settings._dateFormatHandling != null)
|
||
|
{
|
||
|
serializer._dateFormatHandling = settings._dateFormatHandling;
|
||
|
}
|
||
|
if (settings._dateTimeZoneHandling != null)
|
||
|
{
|
||
|
serializer._dateTimeZoneHandling = settings._dateTimeZoneHandling;
|
||
|
}
|
||
|
if (settings._dateParseHandling != null)
|
||
|
{
|
||
|
serializer._dateParseHandling = settings._dateParseHandling;
|
||
|
}
|
||
|
if (settings._dateFormatStringSet)
|
||
|
{
|
||
|
serializer._dateFormatString = settings._dateFormatString;
|
||
|
serializer._dateFormatStringSet = settings._dateFormatStringSet;
|
||
|
}
|
||
|
if (settings._floatFormatHandling != null)
|
||
|
{
|
||
|
serializer._floatFormatHandling = settings._floatFormatHandling;
|
||
|
}
|
||
|
if (settings._floatParseHandling != null)
|
||
|
{
|
||
|
serializer._floatParseHandling = settings._floatParseHandling;
|
||
|
}
|
||
|
if (settings._stringEscapeHandling != null)
|
||
|
{
|
||
|
serializer._stringEscapeHandling = settings._stringEscapeHandling;
|
||
|
}
|
||
|
if (settings._culture != null)
|
||
|
{
|
||
|
serializer._culture = settings._culture;
|
||
|
}
|
||
|
if (settings._maxDepthSet)
|
||
|
{
|
||
|
serializer._maxDepth = settings._maxDepth;
|
||
|
serializer._maxDepthSet = settings._maxDepthSet;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Populates the JSON values onto the target object.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="TextReader"/> that contains the JSON structure to read values from.</param>
|
||
|
/// <param name="target">The target object to populate values onto.</param>
|
||
|
[DebuggerStepThrough]
|
||
|
public void Populate(TextReader reader, object target)
|
||
|
{
|
||
|
Populate(new JsonTextReader(reader), target);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Populates the JSON values onto the target object.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="JsonReader"/> that contains the JSON structure to read values from.</param>
|
||
|
/// <param name="target">The target object to populate values onto.</param>
|
||
|
[DebuggerStepThrough]
|
||
|
public void Populate(JsonReader reader, object target)
|
||
|
{
|
||
|
PopulateInternal(reader, target);
|
||
|
}
|
||
|
|
||
|
internal virtual void PopulateInternal(JsonReader reader, object target)
|
||
|
{
|
||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||
|
ValidationUtils.ArgumentNotNull(target, nameof(target));
|
||
|
|
||
|
SetupReader(
|
||
|
reader,
|
||
|
out CultureInfo? previousCulture,
|
||
|
out DateTimeZoneHandling? previousDateTimeZoneHandling,
|
||
|
out DateParseHandling? previousDateParseHandling,
|
||
|
out FloatParseHandling? previousFloatParseHandling,
|
||
|
out int? previousMaxDepth,
|
||
|
out string? previousDateFormatString);
|
||
|
|
||
|
TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
|
||
|
? CreateTraceJsonReader(reader)
|
||
|
: null;
|
||
|
|
||
|
JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
|
||
|
serializerReader.Populate(traceJsonReader ?? reader, target);
|
||
|
|
||
|
if (traceJsonReader != null)
|
||
|
{
|
||
|
TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
|
||
|
}
|
||
|
|
||
|
ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deserializes the JSON structure contained by the specified <see cref="JsonReader"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="JsonReader"/> that contains the JSON structure to deserialize.</param>
|
||
|
/// <returns>The <see cref="Object"/> being deserialized.</returns>
|
||
|
[DebuggerStepThrough]
|
||
|
public object? Deserialize(JsonReader reader)
|
||
|
{
|
||
|
return Deserialize(reader, null);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deserializes the JSON structure contained by the specified <see cref="TextReader"/>
|
||
|
/// into an instance of the specified type.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="TextReader"/> containing the object.</param>
|
||
|
/// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
|
||
|
/// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
|
||
|
[DebuggerStepThrough]
|
||
|
public object? Deserialize(TextReader reader, Type objectType)
|
||
|
{
|
||
|
return Deserialize(new JsonTextReader(reader), objectType);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deserializes the JSON structure contained by the specified <see cref="JsonReader"/>
|
||
|
/// into an instance of the specified type.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="JsonReader"/> containing the object.</param>
|
||
|
/// <typeparam name="T">The type of the object to deserialize.</typeparam>
|
||
|
/// <returns>The instance of <typeparamref name="T"/> being deserialized.</returns>
|
||
|
[DebuggerStepThrough]
|
||
|
public T? Deserialize<T>(JsonReader reader)
|
||
|
{
|
||
|
return (T?)Deserialize(reader, typeof(T));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deserializes the JSON structure contained by the specified <see cref="JsonReader"/>
|
||
|
/// into an instance of the specified type.
|
||
|
/// </summary>
|
||
|
/// <param name="reader">The <see cref="JsonReader"/> containing the object.</param>
|
||
|
/// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
|
||
|
/// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
|
||
|
[DebuggerStepThrough]
|
||
|
public object? Deserialize(JsonReader reader, Type? objectType)
|
||
|
{
|
||
|
return DeserializeInternal(reader, objectType);
|
||
|
}
|
||
|
|
||
|
internal virtual object? DeserializeInternal(JsonReader reader, Type? objectType)
|
||
|
{
|
||
|
ValidationUtils.ArgumentNotNull(reader, nameof(reader));
|
||
|
|
||
|
SetupReader(
|
||
|
reader,
|
||
|
out CultureInfo? previousCulture,
|
||
|
out DateTimeZoneHandling? previousDateTimeZoneHandling,
|
||
|
out DateParseHandling? previousDateParseHandling,
|
||
|
out FloatParseHandling? previousFloatParseHandling,
|
||
|
out int? previousMaxDepth,
|
||
|
out string? previousDateFormatString);
|
||
|
|
||
|
TraceJsonReader? traceJsonReader = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
|
||
|
? CreateTraceJsonReader(reader)
|
||
|
: null;
|
||
|
|
||
|
JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
|
||
|
object? value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
|
||
|
|
||
|
if (traceJsonReader != null)
|
||
|
{
|
||
|
TraceWriter!.Trace(TraceLevel.Verbose, traceJsonReader.GetDeserializedJsonMessage(), null);
|
||
|
}
|
||
|
|
||
|
ResetReader(reader, previousCulture, previousDateTimeZoneHandling, previousDateParseHandling, previousFloatParseHandling, previousMaxDepth, previousDateFormatString);
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
private void SetupReader(JsonReader reader, out CultureInfo? previousCulture, out DateTimeZoneHandling? previousDateTimeZoneHandling, out DateParseHandling? previousDateParseHandling, out FloatParseHandling? previousFloatParseHandling, out int? previousMaxDepth, out string? previousDateFormatString)
|
||
|
{
|
||
|
if (_culture != null && !_culture.Equals(reader.Culture))
|
||
|
{
|
||
|
previousCulture = reader.Culture;
|
||
|
reader.Culture = _culture;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousCulture = null;
|
||
|
}
|
||
|
|
||
|
if (_dateTimeZoneHandling != null && reader.DateTimeZoneHandling != _dateTimeZoneHandling)
|
||
|
{
|
||
|
previousDateTimeZoneHandling = reader.DateTimeZoneHandling;
|
||
|
reader.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousDateTimeZoneHandling = null;
|
||
|
}
|
||
|
|
||
|
if (_dateParseHandling != null && reader.DateParseHandling != _dateParseHandling)
|
||
|
{
|
||
|
previousDateParseHandling = reader.DateParseHandling;
|
||
|
reader.DateParseHandling = _dateParseHandling.GetValueOrDefault();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousDateParseHandling = null;
|
||
|
}
|
||
|
|
||
|
if (_floatParseHandling != null && reader.FloatParseHandling != _floatParseHandling)
|
||
|
{
|
||
|
previousFloatParseHandling = reader.FloatParseHandling;
|
||
|
reader.FloatParseHandling = _floatParseHandling.GetValueOrDefault();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousFloatParseHandling = null;
|
||
|
}
|
||
|
|
||
|
if (_maxDepthSet && reader.MaxDepth != _maxDepth)
|
||
|
{
|
||
|
previousMaxDepth = reader.MaxDepth;
|
||
|
reader.MaxDepth = _maxDepth;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousMaxDepth = null;
|
||
|
}
|
||
|
|
||
|
if (_dateFormatStringSet && reader.DateFormatString != _dateFormatString)
|
||
|
{
|
||
|
previousDateFormatString = reader.DateFormatString;
|
||
|
reader.DateFormatString = _dateFormatString;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
previousDateFormatString = null;
|
||
|
}
|
||
|
|
||
|
if (reader is JsonTextReader textReader)
|
||
|
{
|
||
|
if (textReader.PropertyNameTable == null && _contractResolver is DefaultContractResolver resolver)
|
||
|
{
|
||
|
textReader.PropertyNameTable = resolver.GetNameTable();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void ResetReader(JsonReader reader, CultureInfo? previousCulture, DateTimeZoneHandling? previousDateTimeZoneHandling, DateParseHandling? previousDateParseHandling, FloatParseHandling? previousFloatParseHandling, int? previousMaxDepth, string? previousDateFormatString)
|
||
|
{
|
||
|
// reset reader back to previous options
|
||
|
if (previousCulture != null)
|
||
|
{
|
||
|
reader.Culture = previousCulture;
|
||
|
}
|
||
|
if (previousDateTimeZoneHandling != null)
|
||
|
{
|
||
|
reader.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousDateParseHandling != null)
|
||
|
{
|
||
|
reader.DateParseHandling = previousDateParseHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousFloatParseHandling != null)
|
||
|
{
|
||
|
reader.FloatParseHandling = previousFloatParseHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (_maxDepthSet)
|
||
|
{
|
||
|
reader.MaxDepth = previousMaxDepth;
|
||
|
}
|
||
|
if (_dateFormatStringSet)
|
||
|
{
|
||
|
reader.DateFormatString = previousDateFormatString;
|
||
|
}
|
||
|
|
||
|
if (reader is JsonTextReader textReader && textReader.PropertyNameTable != null &&
|
||
|
_contractResolver is DefaultContractResolver resolver && textReader.PropertyNameTable == resolver.GetNameTable())
|
||
|
{
|
||
|
textReader.PropertyNameTable = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serializes the specified <see cref="Object"/> and writes the JSON structure
|
||
|
/// using the specified <see cref="TextWriter"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="textWriter">The <see cref="TextWriter"/> used to write the JSON structure.</param>
|
||
|
/// <param name="value">The <see cref="Object"/> to serialize.</param>
|
||
|
public void Serialize(TextWriter textWriter, object? value)
|
||
|
{
|
||
|
Serialize(new JsonTextWriter(textWriter), value);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serializes the specified <see cref="Object"/> and writes the JSON structure
|
||
|
/// using the specified <see cref="JsonWriter"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the JSON structure.</param>
|
||
|
/// <param name="value">The <see cref="Object"/> to serialize.</param>
|
||
|
/// <param name="objectType">
|
||
|
/// The type of the value being serialized.
|
||
|
/// This parameter is used when <see cref="JsonSerializer.TypeNameHandling"/> is <see cref="Json.TypeNameHandling.Auto"/> to write out the type name if the type of the value does not match.
|
||
|
/// Specifying the type is optional.
|
||
|
/// </param>
|
||
|
public void Serialize(JsonWriter jsonWriter, object? value, Type? objectType)
|
||
|
{
|
||
|
SerializeInternal(jsonWriter, value, objectType);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serializes the specified <see cref="Object"/> and writes the JSON structure
|
||
|
/// using the specified <see cref="TextWriter"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="textWriter">The <see cref="TextWriter"/> used to write the JSON structure.</param>
|
||
|
/// <param name="value">The <see cref="Object"/> to serialize.</param>
|
||
|
/// <param name="objectType">
|
||
|
/// The type of the value being serialized.
|
||
|
/// This parameter is used when <see cref="TypeNameHandling"/> is Auto to write out the type name if the type of the value does not match.
|
||
|
/// Specifying the type is optional.
|
||
|
/// </param>
|
||
|
public void Serialize(TextWriter textWriter, object? value, Type objectType)
|
||
|
{
|
||
|
Serialize(new JsonTextWriter(textWriter), value, objectType);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serializes the specified <see cref="Object"/> and writes the JSON structure
|
||
|
/// using the specified <see cref="JsonWriter"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the JSON structure.</param>
|
||
|
/// <param name="value">The <see cref="Object"/> to serialize.</param>
|
||
|
public void Serialize(JsonWriter jsonWriter, object? value)
|
||
|
{
|
||
|
SerializeInternal(jsonWriter, value, null);
|
||
|
}
|
||
|
|
||
|
private TraceJsonReader CreateTraceJsonReader(JsonReader reader)
|
||
|
{
|
||
|
TraceJsonReader traceReader = new TraceJsonReader(reader);
|
||
|
if (reader.TokenType != JsonToken.None)
|
||
|
{
|
||
|
traceReader.WriteCurrentToken();
|
||
|
}
|
||
|
|
||
|
return traceReader;
|
||
|
}
|
||
|
|
||
|
internal virtual void SerializeInternal(JsonWriter jsonWriter, object? value, Type? objectType)
|
||
|
{
|
||
|
ValidationUtils.ArgumentNotNull(jsonWriter, nameof(jsonWriter));
|
||
|
|
||
|
// set serialization options onto writer
|
||
|
Formatting? previousFormatting = null;
|
||
|
if (_formatting != null && jsonWriter.Formatting != _formatting)
|
||
|
{
|
||
|
previousFormatting = jsonWriter.Formatting;
|
||
|
jsonWriter.Formatting = _formatting.GetValueOrDefault();
|
||
|
}
|
||
|
|
||
|
DateFormatHandling? previousDateFormatHandling = null;
|
||
|
if (_dateFormatHandling != null && jsonWriter.DateFormatHandling != _dateFormatHandling)
|
||
|
{
|
||
|
previousDateFormatHandling = jsonWriter.DateFormatHandling;
|
||
|
jsonWriter.DateFormatHandling = _dateFormatHandling.GetValueOrDefault();
|
||
|
}
|
||
|
|
||
|
DateTimeZoneHandling? previousDateTimeZoneHandling = null;
|
||
|
if (_dateTimeZoneHandling != null && jsonWriter.DateTimeZoneHandling != _dateTimeZoneHandling)
|
||
|
{
|
||
|
previousDateTimeZoneHandling = jsonWriter.DateTimeZoneHandling;
|
||
|
jsonWriter.DateTimeZoneHandling = _dateTimeZoneHandling.GetValueOrDefault();
|
||
|
}
|
||
|
|
||
|
FloatFormatHandling? previousFloatFormatHandling = null;
|
||
|
if (_floatFormatHandling != null && jsonWriter.FloatFormatHandling != _floatFormatHandling)
|
||
|
{
|
||
|
previousFloatFormatHandling = jsonWriter.FloatFormatHandling;
|
||
|
jsonWriter.FloatFormatHandling = _floatFormatHandling.GetValueOrDefault();
|
||
|
}
|
||
|
|
||
|
StringEscapeHandling? previousStringEscapeHandling = null;
|
||
|
if (_stringEscapeHandling != null && jsonWriter.StringEscapeHandling != _stringEscapeHandling)
|
||
|
{
|
||
|
previousStringEscapeHandling = jsonWriter.StringEscapeHandling;
|
||
|
jsonWriter.StringEscapeHandling = _stringEscapeHandling.GetValueOrDefault();
|
||
|
}
|
||
|
|
||
|
CultureInfo? previousCulture = null;
|
||
|
if (_culture != null && !_culture.Equals(jsonWriter.Culture))
|
||
|
{
|
||
|
previousCulture = jsonWriter.Culture;
|
||
|
jsonWriter.Culture = _culture;
|
||
|
}
|
||
|
|
||
|
string? previousDateFormatString = null;
|
||
|
if (_dateFormatStringSet && jsonWriter.DateFormatString != _dateFormatString)
|
||
|
{
|
||
|
previousDateFormatString = jsonWriter.DateFormatString;
|
||
|
jsonWriter.DateFormatString = _dateFormatString;
|
||
|
}
|
||
|
|
||
|
TraceJsonWriter? traceJsonWriter = (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
|
||
|
? new TraceJsonWriter(jsonWriter)
|
||
|
: null;
|
||
|
|
||
|
JsonSerializerInternalWriter serializerWriter = new JsonSerializerInternalWriter(this);
|
||
|
serializerWriter.Serialize(traceJsonWriter ?? jsonWriter, value, objectType);
|
||
|
|
||
|
if (traceJsonWriter != null)
|
||
|
{
|
||
|
TraceWriter!.Trace(TraceLevel.Verbose, traceJsonWriter.GetSerializedJsonMessage(), null);
|
||
|
}
|
||
|
|
||
|
// reset writer back to previous options
|
||
|
if (previousFormatting != null)
|
||
|
{
|
||
|
jsonWriter.Formatting = previousFormatting.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousDateFormatHandling != null)
|
||
|
{
|
||
|
jsonWriter.DateFormatHandling = previousDateFormatHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousDateTimeZoneHandling != null)
|
||
|
{
|
||
|
jsonWriter.DateTimeZoneHandling = previousDateTimeZoneHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousFloatFormatHandling != null)
|
||
|
{
|
||
|
jsonWriter.FloatFormatHandling = previousFloatFormatHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (previousStringEscapeHandling != null)
|
||
|
{
|
||
|
jsonWriter.StringEscapeHandling = previousStringEscapeHandling.GetValueOrDefault();
|
||
|
}
|
||
|
if (_dateFormatStringSet)
|
||
|
{
|
||
|
jsonWriter.DateFormatString = previousDateFormatString;
|
||
|
}
|
||
|
if (previousCulture != null)
|
||
|
{
|
||
|
jsonWriter.Culture = previousCulture;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal IReferenceResolver GetReferenceResolver()
|
||
|
{
|
||
|
if (_referenceResolver == null)
|
||
|
{
|
||
|
_referenceResolver = new DefaultReferenceResolver();
|
||
|
}
|
||
|
|
||
|
return _referenceResolver;
|
||
|
}
|
||
|
|
||
|
internal JsonConverter? GetMatchingConverter(Type type)
|
||
|
{
|
||
|
return GetMatchingConverter(_converters, type);
|
||
|
}
|
||
|
|
||
|
internal static JsonConverter? GetMatchingConverter(IList<JsonConverter>? converters, Type objectType)
|
||
|
{
|
||
|
#if DEBUG
|
||
|
ValidationUtils.ArgumentNotNull(objectType, nameof(objectType));
|
||
|
#endif
|
||
|
|
||
|
if (converters != null)
|
||
|
{
|
||
|
for (int i = 0; i < converters.Count; i++)
|
||
|
{
|
||
|
JsonConverter converter = converters[i];
|
||
|
|
||
|
if (converter.CanConvert(objectType))
|
||
|
{
|
||
|
return converter;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
internal void OnError(ErrorEventArgs e)
|
||
|
{
|
||
|
Error?.Invoke(this, e);
|
||
|
}
|
||
|
}
|
||
|
}
|