using System; using System.Linq; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Threading; using ServiceStack.Text.Common; using ServiceStack.Text.Json; using ServiceStack.Text.Jsv; namespace ServiceStack.Text { public static class JsConfig { static JsConfig() { //In-built default serialization, to Deserialize Color struct do: //JsConfig.SerializeFn = c => c.ToString().Replace("Color ", "").Replace("[", "").Replace("]", ""); //JsConfig.DeSerializeFn = System.Drawing.Color.FromName; Reset(); LicenseUtils.Init(); } public static JsConfigScope BeginScope() { return new JsConfigScope(); } public static JsConfigScope With( bool? convertObjectTypesIntoStringDictionary = null, bool? tryToParsePrimitiveTypeValues = null, bool? tryToParseNumericType = null, ParseAsType? parsePrimitiveFloatingPointTypes = null, ParseAsType? parsePrimitiveIntegerTypes = null, bool? includeNullValues = null, bool? includeDefaultEnums = null, bool? excludeTypeInfo = null, bool? includeTypeInfo = null, bool? emitCamelCaseNames = null, bool? emitLowercaseUnderscoreNames = null, DateHandler? dateHandler = null, TimeSpanHandler? timeSpanHandler = null, PropertyConvention? propertyConvention = null, bool? preferInterfaces = null, bool? throwOnDeserializationError = null, string typeAttr = null, Func typeWriter = null, Func typeFinder = null, bool? treatEnumAsInteger = null, bool? alwaysUseUtc = null, bool? assumeUtc = null, bool? appendUtcOffset = null, bool? escapeUnicode = null, bool? includePublicFields = null, bool? reuseStringBuffer = null, int? maxDepth = null, EmptyCtorFactoryDelegate modelFactory = null, string[] excludePropertyReferences = null) { return new JsConfigScope { ConvertObjectTypesIntoStringDictionary = convertObjectTypesIntoStringDictionary ?? sConvertObjectTypesIntoStringDictionary, TryToParsePrimitiveTypeValues = tryToParsePrimitiveTypeValues ?? sTryToParsePrimitiveTypeValues, TryToParseNumericType = tryToParseNumericType ?? sTryToParseNumericType, ParsePrimitiveFloatingPointTypes = parsePrimitiveFloatingPointTypes ?? sParsePrimitiveFloatingPointTypes, ParsePrimitiveIntegerTypes = parsePrimitiveIntegerTypes ?? sParsePrimitiveIntegerTypes, IncludeNullValues = includeNullValues ?? sIncludeNullValues, IncludeDefaultEnums = includeDefaultEnums ?? sIncludeDefaultEnums, ExcludeTypeInfo = excludeTypeInfo ?? sExcludeTypeInfo, IncludeTypeInfo = includeTypeInfo ?? sIncludeTypeInfo, EmitCamelCaseNames = emitCamelCaseNames ?? sEmitCamelCaseNames, EmitLowercaseUnderscoreNames = emitLowercaseUnderscoreNames ?? sEmitLowercaseUnderscoreNames, DateHandler = dateHandler ?? sDateHandler, TimeSpanHandler = timeSpanHandler ?? sTimeSpanHandler, PropertyConvention = propertyConvention ?? sPropertyConvention, PreferInterfaces = preferInterfaces ?? sPreferInterfaces, ThrowOnDeserializationError = throwOnDeserializationError ?? sThrowOnDeserializationError, TypeAttr = typeAttr ?? sTypeAttr, TypeWriter = typeWriter ?? sTypeWriter, TypeFinder = typeFinder ?? sTypeFinder, TreatEnumAsInteger = treatEnumAsInteger ?? sTreatEnumAsInteger, AlwaysUseUtc = alwaysUseUtc ?? sAlwaysUseUtc, AssumeUtc = assumeUtc ?? sAssumeUtc, AppendUtcOffset = appendUtcOffset ?? sAppendUtcOffset, EscapeUnicode = escapeUnicode ?? sEscapeUnicode, IncludePublicFields = includePublicFields ?? sIncludePublicFields, ReuseStringBuffer = reuseStringBuffer ?? sReuseStringBuffer, MaxDepth = maxDepth ?? sMaxDepth, ModelFactory = modelFactory ?? ModelFactory, ExcludePropertyReferences = excludePropertyReferences ?? sExcludePropertyReferences }; } private static bool? sConvertObjectTypesIntoStringDictionary; public static bool ConvertObjectTypesIntoStringDictionary { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ConvertObjectTypesIntoStringDictionary : null) ?? sConvertObjectTypesIntoStringDictionary ?? false; } set { if (!sConvertObjectTypesIntoStringDictionary.HasValue) sConvertObjectTypesIntoStringDictionary = value; } } private static bool? sTryToParsePrimitiveTypeValues; public static bool TryToParsePrimitiveTypeValues { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TryToParsePrimitiveTypeValues : null) ?? sTryToParsePrimitiveTypeValues ?? false; } set { if (!sTryToParsePrimitiveTypeValues.HasValue) sTryToParsePrimitiveTypeValues = value; } } private static bool? sTryToParseNumericType; public static bool TryToParseNumericType { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TryToParseNumericType : null) ?? sTryToParseNumericType ?? false; } set { if (!sTryToParseNumericType.HasValue) sTryToParseNumericType = value; } } private static ParseAsType? sParsePrimitiveFloatingPointTypes; public static ParseAsType ParsePrimitiveFloatingPointTypes { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ParsePrimitiveFloatingPointTypes : null) ?? sParsePrimitiveFloatingPointTypes ?? ParseAsType.Decimal; } set { if (sParsePrimitiveFloatingPointTypes == null) sParsePrimitiveFloatingPointTypes = value; } } private static ParseAsType? sParsePrimitiveIntegerTypes; public static ParseAsType ParsePrimitiveIntegerTypes { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ParsePrimitiveIntegerTypes : null) ?? sParsePrimitiveIntegerTypes ?? ParseAsType.Byte | ParseAsType.SByte | ParseAsType.Int16 | ParseAsType.UInt16 | ParseAsType.Int32 | ParseAsType.UInt32 | ParseAsType.Int64 | ParseAsType.UInt64; } set { if (!sParsePrimitiveIntegerTypes.HasValue) sParsePrimitiveIntegerTypes = value; } } private static bool? sIncludeNullValues; public static bool IncludeNullValues { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeNullValues : null) ?? sIncludeNullValues ?? false; } set { if (!sIncludeNullValues.HasValue) sIncludeNullValues = value; } } private static bool? sIncludeDefaultEnums; public static bool IncludeDefaultEnums { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeDefaultEnums : null) ?? sIncludeDefaultEnums ?? true; } set { if (!sIncludeDefaultEnums.HasValue) sIncludeDefaultEnums = value; } } private static bool? sTreatEnumAsInteger; public static bool TreatEnumAsInteger { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TreatEnumAsInteger : null) ?? sTreatEnumAsInteger ?? false; } set { if (!sTreatEnumAsInteger.HasValue) sTreatEnumAsInteger = value; } } private static bool? sExcludeTypeInfo; public static bool ExcludeTypeInfo { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ExcludeTypeInfo : null) ?? sExcludeTypeInfo ?? false; } set { if (!sExcludeTypeInfo.HasValue) sExcludeTypeInfo = value; } } private static bool? sIncludeTypeInfo; public static bool IncludeTypeInfo { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeTypeInfo : null) ?? sIncludeTypeInfo ?? false; } set { if (!sIncludeTypeInfo.HasValue) sIncludeTypeInfo = value; } } private static string sTypeAttr; public static string TypeAttr { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeAttr : null) ?? sTypeAttr ?? JsWriter.TypeAttr; } set { if (sTypeAttr == null) sTypeAttr = value; JsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(value); JsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(value); } } private static string sJsonTypeAttrInObject; private static readonly string defaultJsonTypeAttrInObject = JsonTypeSerializer.GetTypeAttrInObject(TypeAttr); internal static string JsonTypeAttrInObject { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.JsonTypeAttrInObject : null) ?? sJsonTypeAttrInObject ?? defaultJsonTypeAttrInObject; } set { if (sJsonTypeAttrInObject == null) sJsonTypeAttrInObject = value; } } private static string sJsvTypeAttrInObject; private static readonly string defaultJsvTypeAttrInObject = JsvTypeSerializer.GetTypeAttrInObject(TypeAttr); internal static string JsvTypeAttrInObject { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.JsvTypeAttrInObject : null) ?? sJsvTypeAttrInObject ?? defaultJsvTypeAttrInObject; } set { if (sJsvTypeAttrInObject == null) sJsvTypeAttrInObject = value; } } private static Func sTypeWriter; public static Func TypeWriter { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeWriter : null) ?? sTypeWriter ?? AssemblyUtils.WriteType; } set { if (sTypeWriter == null) sTypeWriter = value; } } private static Func sTypeFinder; public static Func TypeFinder { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeFinder : null) ?? sTypeFinder ?? AssemblyUtils.FindType; } set { if (sTypeFinder == null) sTypeFinder = value; } } private static DateHandler? sDateHandler; public static DateHandler DateHandler { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.DateHandler : null) ?? sDateHandler ?? DateHandler.TimestampOffset; } set { if (!sDateHandler.HasValue) sDateHandler = value; } } /// /// Sets which format to use when serializing TimeSpans /// private static TimeSpanHandler? sTimeSpanHandler; public static TimeSpanHandler TimeSpanHandler { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.TimeSpanHandler : null) ?? sTimeSpanHandler ?? TimeSpanHandler.DurationFormat; } set { if (!sTimeSpanHandler.HasValue) sTimeSpanHandler = value; } } /// /// if the is configured /// to take advantage of specification, /// to support user-friendly serialized formats, ie emitting camelCasing for JSON /// and parsing member names and enum values in a case-insensitive manner. /// private static bool? sEmitCamelCaseNames; public static bool EmitCamelCaseNames { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitCamelCaseNames : null) ?? sEmitCamelCaseNames ?? false; } set { if (!sEmitCamelCaseNames.HasValue) sEmitCamelCaseNames = value; } } /// /// if the is configured /// to support web-friendly serialized formats, ie emitting lowercase_underscore_casing for JSON /// private static bool? sEmitLowercaseUnderscoreNames; public static bool EmitLowercaseUnderscoreNames { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitLowercaseUnderscoreNames : null) ?? sEmitLowercaseUnderscoreNames ?? false; } set { if (!sEmitLowercaseUnderscoreNames.HasValue) sEmitLowercaseUnderscoreNames = value; } } /// /// Define how property names are mapped during deserialization /// private static PropertyConvention? sPropertyConvention; public static PropertyConvention PropertyConvention { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.PropertyConvention : null) ?? sPropertyConvention ?? PropertyConvention.Strict; } set { if (!sPropertyConvention.HasValue) sPropertyConvention = value; } } /// /// Gets or sets a value indicating if the framework should throw serialization exceptions /// or continue regardless of deserialization errors. If the framework /// will throw; otherwise, it will parse as many fields as possible. The default is . /// private static bool? sThrowOnDeserializationError; public static bool ThrowOnDeserializationError { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ThrowOnDeserializationError : null) ?? sThrowOnDeserializationError ?? false; } set { if (!sThrowOnDeserializationError.HasValue) sThrowOnDeserializationError = value; } } /// /// Gets or sets a value indicating if the framework should always convert to UTC format instead of local time. /// private static bool? sAlwaysUseUtc; public static bool AlwaysUseUtc { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.AlwaysUseUtc : null) ?? sAlwaysUseUtc ?? false; } set { if (!sAlwaysUseUtc.HasValue) sAlwaysUseUtc = value; } } /// /// Gets or sets a value indicating if the framework should always assume is in UTC format if Kind is Unspecified. /// private static bool? sAssumeUtc; public static bool AssumeUtc { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.AssumeUtc : null) ?? sAssumeUtc ?? false; } set { if (!sAssumeUtc.HasValue) sAssumeUtc = value; } } /// /// Gets or sets whether we should append the Utc offset when we serialize Utc dates. Defaults to no. /// Only supported for when the JsConfig.DateHandler == JsonDateHandler.TimestampOffset /// private static bool? sAppendUtcOffset; public static bool? AppendUtcOffset { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.AppendUtcOffset : null) ?? sAppendUtcOffset ?? null; } set { if (sAppendUtcOffset == null) sAppendUtcOffset = value; } } /// /// Gets or sets a value indicating if unicode symbols should be serialized as "\uXXXX". /// private static bool? sEscapeUnicode; public static bool EscapeUnicode { // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { return (JsConfigScope.Current != null ? JsConfigScope.Current.EscapeUnicode : null) ?? sEscapeUnicode ?? false; } set { if (!sEscapeUnicode.HasValue) sEscapeUnicode = value; } } internal static HashSet HasSerializeFn = new HashSet(); internal static HashSet HasIncludeDefaultValue = new HashSet(); public static HashSet TreatValueAsRefTypes = new HashSet(); private static bool? sPreferInterfaces; /// /// If set to true, Interface types will be prefered over concrete types when serializing. /// public static bool PreferInterfaces { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.PreferInterfaces : null) ?? sPreferInterfaces ?? false; } set { if (!sPreferInterfaces.HasValue) sPreferInterfaces = value; } } internal static bool TreatAsRefType(Type valueType) { return TreatValueAsRefTypes.Contains(valueType.IsGeneric() ? valueType.GenericTypeDefinition() : valueType); } /// /// If set to true, Interface types will be prefered over concrete types when serializing. /// private static bool? sIncludePublicFields; public static bool IncludePublicFields { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludePublicFields : null) ?? sIncludePublicFields ?? false; } set { if (!sIncludePublicFields.HasValue) sIncludePublicFields = value; } } /// /// For extra serialization performance you can re-use a ThreadStatic StringBuilder /// when serializing to a JSON String. /// private static bool? sReuseStringBuffer; public static bool ReuseStringBuffer { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ReuseStringBuffer : null) ?? sReuseStringBuffer ?? true; } set { if (!sReuseStringBuffer.HasValue) sReuseStringBuffer = value; } } /// /// Sets the maximum depth to avoid circular dependencies /// private static int? sMaxDepth; public static int MaxDepth { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.MaxDepth : null) ?? sMaxDepth ?? int.MaxValue; } set { if (!sMaxDepth.HasValue) sMaxDepth = value; } } /// /// Set this to enable your own type construction provider. /// This is helpful for integration with IoC containers where you need to call the container constructor. /// Return null if you don't know how to construct the type and the parameterless constructor will be used. /// private static EmptyCtorFactoryDelegate sModelFactory; public static EmptyCtorFactoryDelegate ModelFactory { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ModelFactory : null) ?? sModelFactory ?? null; } set { if (sModelFactory != null) sModelFactory = value; } } private static string[] sExcludePropertyReferences; public static string[] ExcludePropertyReferences { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ExcludePropertyReferences : null) ?? sExcludePropertyReferences; } set { if (sExcludePropertyReferences != null) sExcludePropertyReferences = value; } } private static HashSet sExcludeTypes; public static HashSet ExcludeTypes { get { return (JsConfigScope.Current != null ? JsConfigScope.Current.ExcludeTypes : null) ?? sExcludeTypes; } set { if (sExcludePropertyReferences != null) sExcludeTypes = value; } } public static string[] IgnoreAttributesNamed { set { ReflectionExtensions.IgnoreAttributesNamed = value; } } public static void Reset() { foreach (var rawSerializeType in HasSerializeFn.ToArray()) { Reset(rawSerializeType); } foreach (var rawSerializeType in HasIncludeDefaultValue.ToArray()) { Reset(rawSerializeType); } foreach (var uniqueType in __uniqueTypes.ToArray()) { Reset(uniqueType); } sModelFactory = ReflectionExtensions.GetConstructorMethodToCache; sTryToParsePrimitiveTypeValues = null; sTryToParseNumericType = null; sConvertObjectTypesIntoStringDictionary = null; sIncludeNullValues = null; sExcludeTypeInfo = null; sEmitCamelCaseNames = null; sEmitLowercaseUnderscoreNames = null; sDateHandler = null; sTimeSpanHandler = null; sPreferInterfaces = null; sThrowOnDeserializationError = null; sTypeAttr = null; sJsonTypeAttrInObject = null; sJsvTypeAttrInObject = null; sTypeWriter = null; sTypeFinder = null; sTreatEnumAsInteger = null; sAlwaysUseUtc = null; sAssumeUtc = null; sAppendUtcOffset = null; sEscapeUnicode = null; sIncludePublicFields = null; sReuseStringBuffer = null; HasSerializeFn = new HashSet(); HasIncludeDefaultValue = new HashSet(); TreatValueAsRefTypes = new HashSet { typeof(KeyValuePair<,>) }; sPropertyConvention = null; sExcludePropertyReferences = null; sExcludeTypes = new HashSet { typeof(Stream) }; __uniqueTypes = new HashSet(); sMaxDepth = 50; sParsePrimitiveIntegerTypes = null; sParsePrimitiveFloatingPointTypes = null; PlatformExtensions.ClearRuntimeAttributes(); ReflectionExtensions.Reset(); JsState.Reset(); } static void Reset(Type cachesForType) { typeof(JsConfig<>).MakeGenericType(new[] { cachesForType }).InvokeReset(); typeof(TypeConfig<>).MakeGenericType(new[] { cachesForType }).InvokeReset(); } internal static void InvokeReset(this Type genericType) { var methodInfo = genericType.GetStaticMethod("Reset"); methodInfo.Invoke(null, null); } internal static HashSet __uniqueTypes = new HashSet(); internal static int __uniqueTypesCount = 0; internal static void AddUniqueType(Type type) { if (__uniqueTypes.Contains(type)) return; HashSet newTypes, snapshot; do { snapshot = __uniqueTypes; newTypes = new HashSet(__uniqueTypes) { type }; __uniqueTypesCount = newTypes.Count; } while (!ReferenceEquals( Interlocked.CompareExchange(ref __uniqueTypes, newTypes, snapshot), snapshot)); } } public class JsConfig { /// /// Always emit type info for this type. Takes precedence over ExcludeTypeInfo /// public static bool? IncludeTypeInfo = null; /// /// Never emit type info for this type /// public static bool? ExcludeTypeInfo = null; /// /// if the is configured /// to take advantage of specification, /// to support user-friendly serialized formats, ie emitting camelCasing for JSON /// and parsing member names and enum values in a case-insensitive manner. /// public static bool? EmitCamelCaseNames = null; public static bool? EmitLowercaseUnderscoreNames = null; public static bool IncludeDefaultValue { get { return JsConfig.HasIncludeDefaultValue.Contains(typeof(T)); } set { if (value) JsConfig.HasIncludeDefaultValue.Add(typeof(T)); else JsConfig.HasIncludeDefaultValue.Remove(typeof(T)); ClearFnCaches(); } } /// /// Define custom serialization fn for BCL Structs /// private static Func serializeFn; public static Func SerializeFn { get { return serializeFn; } set { serializeFn = value; if (value != null) JsConfig.HasSerializeFn.Add(typeof(T)); else JsConfig.HasSerializeFn.Remove(typeof(T)); ClearFnCaches(); } } /// /// Opt-in flag to set some Value Types to be treated as a Ref Type /// public static bool TreatValueAsRefType { get { return JsConfig.TreatValueAsRefTypes.Contains(typeof(T)); } set { if (value) JsConfig.TreatValueAsRefTypes.Add(typeof(T)); else JsConfig.TreatValueAsRefTypes.Remove(typeof(T)); } } /// /// Whether there is a fn (raw or otherwise) /// public static bool HasSerializeFn { get { return !JsState.InSerializer() && (serializeFn != null || rawSerializeFn != null); } } /// /// Define custom raw serialization fn /// private static Func rawSerializeFn; public static Func RawSerializeFn { get { return rawSerializeFn; } set { rawSerializeFn = value; if (value != null) JsConfig.HasSerializeFn.Add(typeof(T)); else JsConfig.HasSerializeFn.Remove(typeof(T)); ClearFnCaches(); } } /// /// Define custom serialization hook /// private static Func onSerializingFn; public static Func OnSerializingFn { get { return onSerializingFn; } set { onSerializingFn = value; } } /// /// Define custom after serialization hook /// private static Action onSerializedFn; public static Action OnSerializedFn { get { return onSerializedFn; } set { onSerializedFn = value; } } /// /// Define custom deserialization fn for BCL Structs /// public static Func DeSerializeFn; /// /// Define custom raw deserialization fn for objects /// public static Func RawDeserializeFn; public static bool HasDeserializeFn { get { return !JsState.InDeserializer() && (DeSerializeFn != null || RawDeserializeFn != null); } } private static Func onDeserializedFn; public static Func OnDeserializedFn { get { return onDeserializedFn; } set { onDeserializedFn = value; } } public static bool HasDeserialingFn { get { return OnDeserializingFn != null; } } private static Func onDeserializingFn; public static Func OnDeserializingFn { get { return onDeserializingFn; } set { onDeserializingFn = value; } } /// /// Exclude specific properties of this type from being serialized /// public static string[] ExcludePropertyNames; public static void WriteFn(TextWriter writer, object obj) { if (RawSerializeFn != null && !JsState.InSerializer()) { JsState.RegisterSerializer(); try { writer.Write(RawSerializeFn((T)obj)); } finally { JsState.UnRegisterSerializer(); } } else if (SerializeFn != null && !JsState.InSerializer()) { JsState.RegisterSerializer(); try { var serializer = JsWriter.GetTypeSerializer(); serializer.WriteString(writer, SerializeFn((T)obj)); } finally { JsState.UnRegisterSerializer(); } } else { var writerFn = JsonWriter.Instance.GetWriteFn(); writerFn(writer, obj); } } public static object ParseFn(string str) { return DeSerializeFn(str); } internal static object ParseFn(ITypeSerializer serializer, string str) { if (RawDeserializeFn != null && !JsState.InDeserializer()) { JsState.RegisterDeserializer(); try { return RawDeserializeFn(str); } finally { JsState.UnRegisterDeserializer(); } } else if (DeSerializeFn != null && !JsState.InDeserializer()) { JsState.RegisterDeserializer(); try { return DeSerializeFn(serializer.UnescapeString(str)); } finally { JsState.UnRegisterDeserializer(); } } else { var parseFn = JsonReader.Instance.GetParseFn(); return parseFn(str); } } internal static void ClearFnCaches() { typeof(JsonWriter<>).MakeGenericType(new[] { typeof(T) }).InvokeReset(); typeof(JsvWriter<>).MakeGenericType(new[] { typeof(T) }).InvokeReset(); } public static void Reset() { RawSerializeFn = null; DeSerializeFn = null; ExcludePropertyNames = null; EmitCamelCaseNames = EmitLowercaseUnderscoreNames = IncludeTypeInfo = ExcludeTypeInfo = null; } } public enum PropertyConvention { /// /// The property names on target types must match property names in the JSON source /// Strict, /// /// The property names on target types may not match the property names in the JSON source /// Lenient } public enum DateHandler { TimestampOffset, DCJSCompatible, ISO8601, RFC1123, UnixTime, UnixTimeMs, } public enum TimeSpanHandler { /// /// Uses the xsd format like PT15H10M20S /// DurationFormat, /// /// Uses the standard .net ToString method of the TimeSpan class /// StandardFormat } }