/// <summary> /// Objects the type of the string to. /// </summary> /// <param name="strType">Type of the string.</param> /// <returns>System.Object.</returns> public static object ObjectStringToType(ReadOnlySpan <char> strType) { var type = ExtractType(strType); if (type != null) { var parseFn = Serializer.GetParseStringSpanFn(type); var propertyValue = parseFn(strType); return(propertyValue); } var config = JsConfig.GetConfig(); if (config.ConvertObjectTypesIntoStringDictionary && !strType.IsNullOrEmpty()) { var firstChar = strType[0]; var endChar = strType[strType.Length - 1]; switch (firstChar) { case JsWriter.MapStartChar when endChar == JsWriter.MapEndChar: { var dynamicMatch = DeserializeDictionary <TSerializer> .ParseDictionary <string, object>(strType, null, v => Serializer.UnescapeString(v).ToString(), v => Serializer.UnescapeString(v).ToString()); if (dynamicMatch is { Count : > 0 }) { return(dynamicMatch); } break; }
/// <summary> /// Parses the dictionary. /// </summary> /// <typeparam name="TKey">The type of the t key.</typeparam> /// <typeparam name="TValue">The type of the t value.</typeparam> /// <param name="value">The value.</param> /// <param name="createMapType">Type of the create map.</param> /// <param name="parseKeyFn">The parse key function.</param> /// <param name="parseValueFn">The parse value function.</param> /// <returns>IDictionary<TKey, TValue>.</returns> public static IDictionary <TKey, TValue> ParseDictionary <TKey, TValue>( ReadOnlySpan <char> value, Type createMapType, ParseStringSpanDelegate parseKeyFn, ParseStringSpanDelegate parseValueFn) { if (value.IsEmpty) { return(null); } var to = createMapType == null ? new Dictionary <TKey, TValue>() : (IDictionary <TKey, TValue>)createMapType.CreateInstance(); var objDeserializer = Json.JsonTypeSerializer.Instance.ObjectDeserializer; if (to is Dictionary <string, object> && objDeserializer != null && typeof(TSerializer) == typeof(Json.JsonTypeSerializer)) { return((IDictionary <TKey, TValue>)objDeserializer(value)); } var config = JsConfig.GetConfig(); var tryToParseItemsAsDictionaries = config.ConvertObjectTypesIntoStringDictionary && typeof(TValue) == typeof(object); var tryToParseItemsAsPrimitiveTypes = config.TryToParsePrimitiveTypeValues && typeof(TValue) == typeof(object); var index = VerifyAndGetStartIndex(value, createMapType); if (Json.JsonTypeSerializer.IsEmptyMap(value, index)) { return(to); } var valueLength = value.Length; while (index < valueLength) { var keyValue = Serializer.EatMapKey(value, ref index); Serializer.EatMapKeySeperator(value, ref index); var elementStartIndex = index; var elementValue = Serializer.EatTypeValue(value, ref index); if (keyValue.IsNullOrEmpty()) { continue; } TKey mapKey = (TKey)parseKeyFn(keyValue); if (tryToParseItemsAsDictionaries) { Serializer.EatWhitespace(value, ref elementStartIndex); if (elementStartIndex < valueLength && value[elementStartIndex] == JsWriter.MapStartChar) { var tmpMap = ParseDictionary <TKey, TValue>(elementValue, createMapType, parseKeyFn, parseValueFn); if (tmpMap is { Count : > 0 })
public static void WriteWcfJsonDate(TextWriter writer, DateTime dateTime) { var config = JsConfig.GetConfig(); dateTime = dateTime.UseConfigSpecifiedSetting(); switch (config.DateHandler) { case DateHandler.ISO8601: writer.Write(dateTime.ToString("o", CultureInfo.InvariantCulture)); return; case DateHandler.ISO8601DateOnly: writer.Write(dateTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)); return; case DateHandler.ISO8601DateTime: writer.Write(dateTime.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)); return; case DateHandler.RFC1123: writer.Write(dateTime.ToUniversalTime().ToString("R", CultureInfo.InvariantCulture)); return; } var timestamp = dateTime.ToUnixTimeMs(); string offset = null; if (dateTime.Kind != DateTimeKind.Utc) { if (config.DateHandler == DateHandler.TimestampOffset && dateTime.Kind == DateTimeKind.Unspecified) { offset = UnspecifiedOffset; } else { offset = LocalTimeZone.GetUtcOffset(dateTime).ToTimeOffsetString(); } } else { // Normally the JsonDateHandler.TimestampOffset doesn't append an offset for Utc dates, but if // the config.AppendUtcOffset is set then we will if (config.DateHandler == DateHandler.TimestampOffset && config.AppendUtcOffset) { offset = UtcOffset; } } writer.Write(EscapedWcfJsonPrefix); writer.Write(timestamp); if (offset != null) { writer.Write(offset); } writer.Write(EscapedWcfJsonSuffix); }
public static object ParseQuotedPrimitive(string value) { var config = JsConfig.GetConfig(); var fn = config.ParsePrimitiveFn; var result = fn?.Invoke(value); if (result != null) { return(result); } if (string.IsNullOrEmpty(value)) { return(null); } if (Guid.TryParse(value, out Guid guidValue)) { return(guidValue); } if (value.StartsWith(DateTimeSerializer.EscapedWcfJsonPrefix, StringComparison.Ordinal) || value.StartsWith(DateTimeSerializer.WcfJsonPrefix, StringComparison.Ordinal)) { return(DateTimeSerializer.ParseWcfJsonDate(value)); } if (JsConfig.DateHandler == DateHandler.ISO8601) { // check that we have UTC ISO8601 date: // YYYY-MM-DDThh:mm:ssZ // YYYY-MM-DDThh:mm:ss+02:00 // YYYY-MM-DDThh:mm:ss-02:00 if (value.Length > 14 && value[10] == 'T' && (value.EndsWithInvariant("Z") || value[value.Length - 6] == '+' || value[value.Length - 6] == '-')) { return(DateTimeSerializer.ParseShortestXsdDateTime(value)); } } if (config.DateHandler == DateHandler.RFC1123) { // check that we have RFC1123 date: // ddd, dd MMM yyyy HH:mm:ss GMT if (value.Length == 29 && (value.EndsWithInvariant("GMT"))) { return(DateTimeSerializer.ParseRFC1123DateTime(value)); } } return(Serializer.UnescapeString(value)); }
public static string ToShortestXsdDateTimeString(DateTime dateTime) { var config = JsConfig.GetConfig(); dateTime = dateTime.UseConfigSpecifiedSetting(); if (!string.IsNullOrEmpty(config.DateTimeFormat)) { return(dateTime.ToString(config.DateTimeFormat, CultureInfo.InvariantCulture)); } var timeOfDay = dateTime.TimeOfDay; var isStartOfDay = timeOfDay.Ticks == 0; if (isStartOfDay && !config.SkipDateTimeConversion) { return(dateTime.ToString(ShortDateTimeFormat, CultureInfo.InvariantCulture)); } var hasFractionalSecs = (timeOfDay.Milliseconds != 0) || (timeOfDay.Ticks % TimeSpan.TicksPerMillisecond != 0); if (config.SkipDateTimeConversion) { if (!hasFractionalSecs) { return(dateTime.Kind == DateTimeKind.Local ? dateTime.ToString(DateTimeFormatSecondsUtcOffset, CultureInfo.InvariantCulture) : dateTime.Kind == DateTimeKind.Unspecified ? dateTime.ToString(DateTimeFormatSecondsNoOffset, CultureInfo.InvariantCulture) : dateTime.ToStableUniversalTime().ToString(XsdDateTimeFormatSeconds, CultureInfo.InvariantCulture)); } return(dateTime.Kind == DateTimeKind.Local ? dateTime.ToString(DateTimeFormatTicksUtcOffset, CultureInfo.InvariantCulture) : dateTime.Kind == DateTimeKind.Unspecified ? dateTime.ToString(DateTimeFormatTicksNoUtcOffset, CultureInfo.InvariantCulture) : PclExport.Instance.ToXsdDateTimeString(dateTime)); } if (!hasFractionalSecs) { return(dateTime.Kind != DateTimeKind.Utc ? dateTime.ToString(DateTimeFormatSecondsUtcOffset, CultureInfo.InvariantCulture) : dateTime.ToStableUniversalTime().ToString(XsdDateTimeFormatSeconds, CultureInfo.InvariantCulture)); } return(dateTime.Kind != DateTimeKind.Utc ? dateTime.ToString(DateTimeFormatTicksUtcOffset, CultureInfo.InvariantCulture) : PclExport.Instance.ToXsdDateTimeString(dateTime)); }
/// <summary> /// Tries the write type information. /// </summary> /// <param name="writer">The writer.</param> /// <param name="obj">The object.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> private static bool TryWriteTypeInfo(TextWriter writer, object obj) { if (obj == null || ShouldSkipType()) { return(false); } var config = JsConfig.GetConfig(); Serializer.WriteRawString(writer, config.TypeAttr); writer.Write(JsWriter.MapKeySeperator); Serializer.WriteRawString(writer, config.TypeWriter(obj.GetType())); return(true); }
/// <summary> /// Tries the type of the write self. /// </summary> /// <param name="writer">The writer.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> private static bool TryWriteSelfType(TextWriter writer) { if (ShouldSkipType()) { return(false); } var config = JsConfig.GetConfig(); Serializer.WriteRawString(writer, config.TypeAttr); writer.Write(JsWriter.MapKeySeperator); Serializer.WriteRawString(writer, config.TypeWriter(typeof(T))); return(true); }
public static object ObjectStringToType(ReadOnlySpan <char> strType) { var type = ExtractType(strType); if (type != null) { var parseFn = Serializer.GetParseStringSpanFn(type); var propertyValue = parseFn(strType); return(propertyValue); } var config = JsConfig.GetConfig(); if (config.ConvertObjectTypesIntoStringDictionary && !strType.IsNullOrEmpty()) { var firstChar = strType[0]; var endChar = strType[strType.Length - 1]; if (firstChar == JsWriter.MapStartChar && endChar == JsWriter.MapEndChar) { var dynamicMatch = DeserializeDictionary <TSerializer> .ParseDictionary <string, object>(strType, null, v => Serializer.UnescapeString(v).ToString(), v => Serializer.UnescapeString(v).ToString()); if (dynamicMatch != null && dynamicMatch.Count > 0) { return(dynamicMatch); } } if (firstChar == JsWriter.ListStartChar && endChar == JsWriter.ListEndChar) { return(DeserializeList <List <object>, TSerializer> .ParseStringSpan(strType)); } } var primitiveType = config.TryToParsePrimitiveTypeValues ? ParsePrimitive(strType) : null; if (primitiveType != null) { return(primitiveType); } if (Serializer.ObjectDeserializer != null && typeof(TSerializer) == typeof(Json.JsonTypeSerializer)) { return(!strType.IsNullOrEmpty() ? Serializer.ObjectDeserializer(strType) : strType.Value()); } return(Serializer.UnescapeString(strType).Value()); }
/// <summary> /// If AlwaysUseUtc is set to true then convert all DateTime to UTC. If PreserveUtc is set to true then UTC dates will not convert to local /// </summary> /// <param name="dateTime"></param> /// <returns></returns> public static DateTime Prepare(this DateTime dateTime, bool parsedAsUtc = false) { var config = JsConfig.GetConfig(); if (config.SkipDateTimeConversion) { return(dateTime); } if (config.AlwaysUseUtc) { return(dateTime.Kind != DateTimeKind.Utc ? dateTime.ToStableUniversalTime() : dateTime); } return(parsedAsUtc ? dateTime.ToLocalTime() : dateTime); }
public static DateTime?ParseManual(string dateTimeStr) { var config = JsConfig.GetConfig(); var dateKind = config.AssumeUtc || config.AlwaysUseUtc ? DateTimeKind.Utc : DateTimeKind.Local; var date = ParseManual(dateTimeStr, dateKind); if (date == null) { return(null); } return(dateKind == DateTimeKind.Local ? date.Value.ToLocalTime().Prepare() : date); }
public static FieldInfo[] GetSerializableFields(this Type type) { if (type.IsDto()) { return(type.GetAllFields().Where(f => f.HasAttribute <DataMemberAttribute>()).ToArray()); } var config = JsConfig.GetConfig(); if (!config.IncludePublicFields) { return(TypeConstants.EmptyFieldInfoArray); } var publicFields = type.GetPublicFields(); // else return those properties that are not decorated with IgnoreDataMember return(publicFields .Where(prop => prop.GetAllAttributes() .All(attr => !IgnoreAttributesNamed.Contains(attr.GetType().Name))) .Where(prop => !config.ExcludeTypes.Contains(prop.FieldType)) .ToArray()); }
public static DateTime ParseShortestXsdDateTime(string dateTimeStr) { try { if (string.IsNullOrEmpty(dateTimeStr)) { return(DateTime.MinValue); } if (dateTimeStr.StartsWith(EscapedWcfJsonPrefix, StringComparison.Ordinal) || dateTimeStr.StartsWith(WcfJsonPrefix, StringComparison.Ordinal)) { return(ParseWcfJsonDate(dateTimeStr).Prepare()); } var config = JsConfig.GetConfig(); if (dateTimeStr.Length == DefaultDateTimeFormat.Length) { var unspecifiedDate = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); if (config.AssumeUtc) { unspecifiedDate = DateTime.SpecifyKind(unspecifiedDate, DateTimeKind.Utc); } return(unspecifiedDate.Prepare()); } if (dateTimeStr.Length == DefaultDateTimeFormatWithFraction.Length) { var unspecifiedDate = config.AssumeUtc ? DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) : DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture); return(unspecifiedDate.Prepare()); } var kind = DateTimeKind.Unspecified; switch (config.DateHandler) { case DateHandler.UnixTime: if (int.TryParse(dateTimeStr, out var unixTime)) { return(unixTime.FromUnixTime()); } break; case DateHandler.UnixTimeMs: if (long.TryParse(dateTimeStr, out var unixTimeMs)) { return(unixTimeMs.FromUnixTimeMs()); } break; case DateHandler.ISO8601: case DateHandler.ISO8601DateOnly: case DateHandler.ISO8601DateTime: if (config.SkipDateTimeConversion) { dateTimeStr = RemoveUtcOffsets(dateTimeStr, out kind); } break; } dateTimeStr = RepairXsdTimeSeparator(dateTimeStr); if (dateTimeStr.Length == XsdDateTimeFormatSeconds.Length) { return(DateTime.ParseExact(dateTimeStr, XsdDateTimeFormatSeconds, null, DateTimeStyles.AdjustToUniversal).Prepare(parsedAsUtc: true)); } if (dateTimeStr.Length >= XsdDateTimeFormat3F.Length && dateTimeStr.Length <= XsdDateTimeFormat.Length && dateTimeStr.EndsWith(XsdUtcSuffix)) { var dateTime = Env.IsMono ? ParseManual(dateTimeStr) : null; if (dateTime != null) { return(dateTime.Value); } return(PclExport.Instance.ParseXsdDateTimeAsUtc(dateTimeStr)); } if (dateTimeStr.Length == CondensedDateTimeFormat.Length && dateTimeStr.IndexOfAny(DateTimeSeperators) == -1) { return(DateTime.ParseExact(dateTimeStr, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None)); } if (dateTimeStr.Length == ShortDateTimeFormat.Length) { try { var manualDate = ParseManual(dateTimeStr); if (manualDate != null) { return(manualDate.Value); } } catch { } } try { if (config.SkipDateTimeConversion) { return(DateTime.Parse(dateTimeStr, null, kind == DateTimeKind.Unspecified ? DateTimeStyles.None : kind == DateTimeKind.Local ? DateTimeStyles.AssumeLocal : DateTimeStyles.AssumeUniversal)); } var assumeKind = config.AssumeUtc ? DateTimeStyles.AssumeUniversal : DateTimeStyles.AssumeLocal; var dateTime = DateTime.Parse(dateTimeStr, CultureInfo.InvariantCulture, assumeKind); return(dateTime.Prepare()); } catch (FormatException) { var manualDate = ParseManual(dateTimeStr); if (manualDate != null) { return(manualDate.Value); } throw; } } catch (Exception ex) { if (OnParseErrorFn != null) { return(OnParseErrorFn(dateTimeStr, ex)); } throw; } }
public static void WriteComplexQueryStringProperties(string typeName, TextWriter writer, object instance) { var i = 0; if (PropertyWriters != null) { var config = JsConfig <T> .GetConfig(); var typedInstance = (T)instance; var len = PropertyWriters.Length; for (var index = 0; index < len; index++) { var propertyWriter = PropertyWriters[index]; if (propertyWriter.shouldSerialize != null && !propertyWriter.shouldSerialize(typedInstance)) { continue; } var propertyValue = instance != null?propertyWriter.GetterFn(typedInstance) : null; if (propertyWriter.propertySuppressDefaultAttribute && Equals(propertyWriter.DefaultValue, propertyValue)) { continue; } if ((propertyValue == null || propertyWriter.propertySuppressDefaultConfig && Equals(propertyWriter.DefaultValue, propertyValue)) && !Serializer.IncludeNullValues) { continue; } if (config.ExcludePropertyReferences != null && config.ExcludePropertyReferences.Contains(propertyWriter.propertyReferenceName)) { continue; } if (i++ > 0) { writer.Write('&'); } var propertyValueType = propertyValue?.GetType(); if (propertyValueType != null && propertyValueType.IsUserType() && !propertyValueType.HasInterface(typeof(IEnumerable))) { //Nested Complex Type: legal_entity[dob][day]=1 var prefix = $"{typeName}[{propertyWriter.GetPropertyName(config)}]"; var props = propertyValueType.GetSerializableProperties(); for (int j = 0; j < props.Length; j++) { var pi = props[j]; var pValue = pi.GetValue(propertyValue, TypeConstants.EmptyObjectArray); if (pValue == null && !Serializer.IncludeNullValues) { continue; } if (j > 0) { writer.Write('&'); } writer.Write(prefix); writer.Write('['); writer.Write(GetPropertyName(pi.Name, config)); writer.Write("]="); if (pValue == null) { writer.Write(JsonUtils.Null); } else { JsvWriter.GetWriteFn(pValue.GetType())(writer, pValue); } } } else { writer.Write(typeName); writer.Write('['); writer.Write(propertyWriter.GetPropertyName(config)); writer.Write("]="); if (propertyValue == null) { writer.Write(JsonUtils.Null); } else { propertyWriter.WriteFn(writer, propertyValue); } } } } }
public static IDictionary <TKey, TValue> ParseDictionary <TKey, TValue>( ReadOnlySpan <char> value, Type createMapType, ParseStringSpanDelegate parseKeyFn, ParseStringSpanDelegate parseValueFn) { if (value.IsEmpty) { return(null); } var config = JsConfig.GetConfig(); var tryToParseItemsAsDictionaries = config.ConvertObjectTypesIntoStringDictionary && typeof(TValue) == typeof(object); var tryToParseItemsAsPrimitiveTypes = config.TryToParsePrimitiveTypeValues && typeof(TValue) == typeof(object); var index = VerifyAndGetStartIndex(value, createMapType); var to = (createMapType == null) ? new Dictionary <TKey, TValue>() : (IDictionary <TKey, TValue>)createMapType.CreateInstance(); if (JsonTypeSerializer.IsEmptyMap(value, index)) { return(to); } var valueLength = value.Length; while (index < valueLength) { var keyValue = Serializer.EatMapKey(value, ref index); Serializer.EatMapKeySeperator(value, ref index); var elementStartIndex = index; var elementValue = Serializer.EatTypeValue(value, ref index); if (keyValue.IsNullOrEmpty()) { continue; } TKey mapKey = (TKey)parseKeyFn(keyValue); if (tryToParseItemsAsDictionaries) { Serializer.EatWhitespace(value, ref elementStartIndex); if (elementStartIndex < valueLength && value[elementStartIndex] == JsWriter.MapStartChar) { var tmpMap = ParseDictionary <TKey, TValue>(elementValue, createMapType, parseKeyFn, parseValueFn); if (tmpMap != null && tmpMap.Count > 0) { to[mapKey] = (TValue)tmpMap; } } else if (elementStartIndex < valueLength && value[elementStartIndex] == JsWriter.ListStartChar) { to[mapKey] = (TValue)DeserializeList <List <object>, TSerializer> .ParseStringSpan(elementValue); } else { to[mapKey] = (TValue)(tryToParseItemsAsPrimitiveTypes && elementStartIndex < valueLength ? DeserializeType <TSerializer> .ParsePrimitive(elementValue.Value(), value[elementStartIndex]) : parseValueFn(elementValue)); } } else { if (tryToParseItemsAsPrimitiveTypes && elementStartIndex < valueLength) { Serializer.EatWhitespace(value, ref elementStartIndex); to[mapKey] = (TValue)DeserializeType <TSerializer> .ParsePrimitive(elementValue.Value(), value[elementStartIndex]); } else { to[mapKey] = (TValue)parseValueFn(elementValue); } } Serializer.EatItemSeperatorOrMapEndChar(value, ref index); } return(to); }
/// <summary> /// Writes the string. /// </summary> /// <param name="writer">The writer.</param> /// <param name="value">The value.</param> public static void WriteString(TextWriter writer, string value) { if (value == null) { writer.Write(Null); return; } var config = JsConfig.GetConfig(); var escapeHtmlChars = config.EscapeHtmlChars; var escapeUnicode = config.EscapeUnicode; if (!HasAnyEscapeChars(value, escapeHtmlChars)) { writer.Write(QuoteChar); writer.Write(value); writer.Write(QuoteChar); return; } var hexSeqBuffer = new char[4]; writer.Write(QuoteChar); var len = value.Length; for (var i = 0; i < len; i++) { char c = value[i]; switch (c) { case LineFeedChar: writer.Write(EscapedLineFeed); continue; case CarriageReturnChar: writer.Write(EscapedCarriageReturn); continue; case TabChar: writer.Write(EscapedTab); continue; case QuoteChar: writer.Write(EscapedQuote); continue; case EscapeChar: writer.Write(EscapedBackslash); continue; case FormFeedChar: writer.Write(EscapedFormFeed); continue; case BackspaceChar: writer.Write(EscapedBackspace); continue; } if (escapeHtmlChars) { switch (c) { case '<': writer.Write("\\u003c"); continue; case '>': writer.Write("\\u003e"); continue; case '&': writer.Write("\\u0026"); continue; case '=': writer.Write("\\u003d"); continue; case '\'': writer.Write("\\u0027"); continue; } } if (c.IsPrintable()) { writer.Write(c); continue; } // http://json.org/ spec requires any control char to be escaped if (escapeUnicode || char.IsControl(c)) { // Default, turn into a \uXXXX sequence IntToHex(c, hexSeqBuffer); writer.Write("\\u"); writer.Write(hexSeqBuffer); } else { writer.Write(c); } } writer.Write(QuoteChar); }
internal static object StringToType(ReadOnlySpan <char> strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair <string, TypeAccessor>[] typeAccessors) { var index = 0; var type = typeConfig.Type; if (strType.IsEmpty) { return(null); } var buffer = strType; var strTypeLength = strType.Length; //if (!Serializer.EatMapStartChar(strType, ref index)) for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline if (buffer[index] != JsWriter.MapStartChar) { throw DeserializeTypeRef.CreateSerializationError(type, strType.ToString()); } index++; if (JsonTypeSerializer.IsEmptyMap(strType, index)) { return(ctorFn()); } var config = JsConfig.GetConfig(); object instance = null; var lenient = config.PropertyConvention == PropertyConvention.Lenient; for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline while (index < strTypeLength) { var propertyName = JsonTypeSerializer.UnescapeJsString(strType, JsonUtils.QuoteChar, removeQuotes: true, ref index); //Serializer.EatMapKeySeperator(strType, ref index); for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline if (strTypeLength != index) { index++; } var propertyValueStr = Serializer.EatValue(strType, ref index); var possibleTypeInfo = propertyValueStr != null && propertyValueStr.Length > 1; //if we already have an instance don't check type info, because then we will have a half deserialized object //we could throw here or just use the existing instance. if (instance == null && possibleTypeInfo && propertyName.Equals(typeAttr.Span, StringComparison.OrdinalIgnoreCase)) { var explicitTypeName = Serializer.ParseString(propertyValueStr); var explicitType = config.TypeFinder(explicitTypeName); if (explicitType == null || explicitType.IsInterface || explicitType.IsAbstract) { Tracer.Instance.WriteWarning("Could not find type: " + propertyValueStr.ToString()); } else if (!type.IsAssignableFrom(explicitType)) { Tracer.Instance.WriteWarning("Could not assign type: " + propertyValueStr.ToString()); } else { JsWriter.AssertAllowedRuntimeType(explicitType); instance = explicitType.CreateInstance(); } if (instance != null) { //If __type info doesn't match, ignore it. if (!type.IsInstanceOfType(instance)) { instance = null; } else { var derivedType = instance.GetType(); if (derivedType != type) { var map = DeserializeTypeRef.GetCachedTypeAccessors(derivedType, Serializer); if (map != null) { typeAccessors = map; } } } } Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); continue; } if (instance == null) { instance = ctorFn(); } var typeAccessor = typeAccessors.Get(propertyName, lenient); var propType = possibleTypeInfo && propertyValueStr[0] == '_' ? TypeAccessor.ExtractType(Serializer, propertyValueStr) : null; if (propType != null) { try { if (typeAccessor != null) { //var parseFn = Serializer.GetParseFn(propType); var parseFn = JsonReader.GetParseStringSpanFn(propType); var propertyValue = parseFn(propertyValueStr); if (typeConfig.OnDeserializing != null) { propertyValue = typeConfig.OnDeserializing(instance, propertyName.ToString(), propertyValue); } typeAccessor.SetProperty(instance, propertyValue); } //Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline if (index != strTypeLength) { var success = buffer[index] == JsWriter.ItemSeperator || buffer[index] == JsWriter.MapEndChar; index++; if (success) { for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline } } continue; } catch (Exception e) { config.OnDeserializationError?.Invoke(instance, propType, propertyName.ToString(), propertyValueStr.ToString(), e); if (config.ThrowOnError) { throw DeserializeTypeRef.GetSerializationException(propertyName.ToString(), propertyValueStr.ToString(), propType, e); } else { Tracer.Instance.WriteWarning("WARN: failed to set dynamic property {0} with: {1}", propertyName.ToString(), propertyValueStr.ToString()); } } } if (typeAccessor?.GetProperty != null && typeAccessor.SetProperty != null) { try { var propertyValue = typeAccessor.GetProperty(propertyValueStr); if (typeConfig.OnDeserializing != null) { propertyValue = typeConfig.OnDeserializing(instance, propertyName.ToString(), propertyValue); } typeAccessor.SetProperty(instance, propertyValue); } catch (NotSupportedException) { throw; } catch (Exception e) { config.OnDeserializationError?.Invoke(instance, propType ?? typeAccessor.PropertyType, propertyName.ToString(), propertyValueStr.ToString(), e); if (config.ThrowOnError) { throw DeserializeTypeRef.GetSerializationException(propertyName.ToString(), propertyValueStr.ToString(), typeAccessor.PropertyType, e); } else { Tracer.Instance.WriteWarning("WARN: failed to set property {0} with: {1}", propertyName.ToString(), propertyValueStr.ToString()); } } } else { // the property is not known by the DTO typeConfig.OnDeserializing?.Invoke(instance, propertyName.ToString(), propertyValueStr.ToString()); } //Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline if (index != strType.Length) { var success = buffer[index] == JsWriter.ItemSeperator || buffer[index] == JsWriter.MapEndChar; index++; if (success) { for (; index < strTypeLength; index++) { if (!JsonUtils.IsWhiteSpace(buffer[index])) { break; } } //Whitespace inline } } } return(instance); }
public static void WriteQueryString(TextWriter writer, object instance) { try { JsState.QueryStringMode = true; var config = JsConfig <T> .GetConfig(); var i = 0; var typedInstance = (T)instance; foreach (var propertyWriter in PropertyWriters) { var propertyValue = propertyWriter.GetterFn(typedInstance); if (propertyValue == null) { continue; } if (i++ > 0) { writer.Write('&'); } var propertyType = propertyValue.GetType(); var strValue = propertyValue as string; var isEnumerable = strValue == null && !propertyType.IsValueType && propertyType.HasInterface(typeof(IEnumerable)); if (QueryStringSerializer.ComplexTypeStrategy != null) { var nonEnumerableUserType = !isEnumerable && (propertyType.IsUserType() || propertyType.IsInterface); if (nonEnumerableUserType || propertyType.IsOrHasGenericInterfaceTypeOf(typeof(IDictionary <,>))) { if (QueryStringSerializer.ComplexTypeStrategy(writer, propertyWriter.GetPropertyName(config), propertyValue)) { continue; } } } Serializer.WritePropertyName(writer, propertyWriter.GetPropertyName(config)); writer.Write('='); if (strValue != null) { writer.Write(strValue.UrlEncode()); } else if (!isEnumerable) { propertyWriter.WriteFn(writer, propertyValue); } else { //Trim brackets in top-level lists in QueryStrings, e.g: ?a=[1,2,3] => ?a=1,2,3 using (var ms = MemoryStreamFactory.GetStream()) { var enumerableWriter = new StreamWriter(ms); //ms disposed in using propertyWriter.WriteFn(enumerableWriter, propertyValue); enumerableWriter.Flush(); var output = ms.ReadToEnd(); output = output.Trim(ArrayBrackets); writer.Write(output); } } } } finally { JsState.QueryStringMode = false; } }
internal static object StringToType(ReadOnlySpan <char> strType, TypeConfig typeConfig, EmptyCtorDelegate ctorFn, KeyValuePair <string, TypeAccessor>[] typeAccessors) { var index = 0; var type = typeConfig.Type; if (strType.IsEmpty) { return(null); } //if (!Serializer.EatMapStartChar(strType, ref index)) if (strType[index++] != JsWriter.MapStartChar) { throw DeserializeTypeRef.CreateSerializationError(type, strType.ToString()); } if (JsonTypeSerializer.IsEmptyMap(strType)) { return(ctorFn()); } var config = JsConfig.GetConfig(); object instance = null; var lenient = config.PropertyConvention == PropertyConvention.Lenient; var strTypeLength = strType.Length; while (index < strTypeLength) { var propertyName = Serializer.EatMapKey(strType, ref index).Trim(); //Serializer.EatMapKeySeperator(strType, ref index); index++; var propertyValueStr = Serializer.EatValue(strType, ref index); var possibleTypeInfo = propertyValueStr != null && propertyValueStr.Length > 1; if (possibleTypeInfo && propertyName.Equals(typeAttr.Span, StringComparison.OrdinalIgnoreCase)) { var explicitTypeName = Serializer.ParseString(propertyValueStr); var explicitType = config.TypeFinder(explicitTypeName); if (explicitType == null || explicitType.IsInterface || explicitType.IsAbstract) { Tracer.Instance.WriteWarning("Could not find type: " + propertyValueStr.ToString()); } else if (!type.IsAssignableFrom(explicitType)) { Tracer.Instance.WriteWarning("Could not assign type: " + propertyValueStr.ToString()); } else { JsWriter.AssertAllowedRuntimeType(explicitType); instance = ActivatorUtils.FastCreateInstance(explicitType); } if (instance != null) { //If __type info doesn't match, ignore it. if (!type.IsInstanceOfType(instance)) { instance = null; } else { var derivedType = instance.GetType(); if (derivedType != type) { var map = DeserializeTypeRef.GetCachedTypeAccessors(derivedType, Serializer); if (map != null) { typeAccessors = map; } } } } //Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); if (index != strType.Length) { index++; } continue; } if (instance == null) { instance = ctorFn(); } var typeAccessor = typeAccessors.Get(propertyName, lenient); var propType = possibleTypeInfo && propertyValueStr[0] == '_' ? TypeAccessor.ExtractType(Serializer, propertyValueStr) : null; if (propType != null) { try { if (typeAccessor != null) { var parseFn = Serializer.GetParseStringSpanFn(propType); var propertyValue = parseFn(propertyValueStr); if (typeConfig.OnDeserializing != null) { propertyValue = typeConfig.OnDeserializing(instance, propertyName.ToString(), propertyValue); } typeAccessor.SetProperty(instance, propertyValue); } //Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); if (index != strType.Length) { index++; } continue; } catch (Exception e) { config.OnDeserializationError?.Invoke(instance, propType, propertyName.ToString(), propertyValueStr.ToString(), e); if (config.ThrowOnError) { throw DeserializeTypeRef.GetSerializationException(propertyName.ToString(), propertyValueStr.ToString(), propType, e); } else { Tracer.Instance.WriteWarning("WARN: failed to set dynamic property {0} with: {1}", propertyName.ToString(), propertyValueStr.ToString()); } } } if (typeAccessor?.GetProperty != null && typeAccessor.SetProperty != null) { try { var propertyValue = typeAccessor.GetProperty(propertyValueStr); if (typeConfig.OnDeserializing != null) { propertyValue = typeConfig.OnDeserializing(instance, propertyName.ToString(), propertyValue); } typeAccessor.SetProperty(instance, propertyValue); } catch (NotSupportedException) { throw; } catch (Exception e) { config.OnDeserializationError?.Invoke(instance, propType ?? typeAccessor.PropertyType, propertyName.ToString(), propertyValueStr.ToString(), e); if (config.ThrowOnError) { throw DeserializeTypeRef.GetSerializationException(propertyName.ToString(), propertyValueStr.ToString(), propType, e); } else { Tracer.Instance.WriteWarning("WARN: failed to set property {0} with: {1}", propertyName.ToString(), propertyValueStr.ToString()); } } } else { // the property is not known by the DTO typeConfig.OnDeserializing?.Invoke(instance, propertyName.ToString(), propertyValueStr.ToString()); } //Serializer.EatItemSeperatorOrMapEndChar(strType, ref index); if (index != strType.Length) { index++; } } return(instance); }
public static object ParseNumber(this ReadOnlySpan <char> value, bool bestFit) { if (value.Length == 1) { int singleDigit = value[0]; if (singleDigit >= 48 || singleDigit <= 57) // 0 - 9 { var result = singleDigit - 48; if (bestFit) { return((byte)result); } return(result); } } var config = JsConfig.GetConfig(); // Parse as decimal var acceptDecimal = config.ParsePrimitiveFloatingPointTypes.Has(ParseAsType.Decimal); var isDecimal = value.TryParseDecimal(out decimal decimalValue); // Check if the number is an Primitive Integer type given that we have a decimal if (isDecimal && decimalValue == decimal.Truncate(decimalValue)) { // Value is a whole number var parseAs = config.ParsePrimitiveIntegerTypes; if (parseAs.Has(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue) { return((byte)decimalValue); } if (parseAs.Has(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue) { return((sbyte)decimalValue); } if (parseAs.Has(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue) { return((Int16)decimalValue); } if (parseAs.Has(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue) { return((UInt16)decimalValue); } if (parseAs.Has(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue) { return((Int32)decimalValue); } if (parseAs.Has(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue) { return((UInt32)decimalValue); } if (parseAs.Has(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue) { return((Int64)decimalValue); } if (parseAs.Has(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue) { return((UInt64)decimalValue); } return(decimalValue); } // Value is a floating point number // Return a decimal if the user accepts a decimal if (isDecimal && acceptDecimal) { return(decimalValue); } var acceptFloat = config.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single); var isFloat = value.TryParseFloat(out float floatValue); if (acceptFloat && isFloat) { return(floatValue); } var acceptDouble = config.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double); var isDouble = value.TryParseDouble(out double doubleValue); if (acceptDouble && isDouble) { return(doubleValue); } if (isDecimal) { return(decimalValue); } if (isFloat) { return(floatValue); } if (isDouble) { return(doubleValue); } return(null); }
public static void WriteProperties(TextWriter writer, object instance) { if (instance == null) { writer.Write(JsWriter.EmptyMap); return; } var valueType = instance.GetType(); if (PropertyWriters != null && valueType != typeof(T) && !typeof(T).IsAbstract) { WriteLateboundProperties(writer, instance, valueType); return; } if (typeof(TSerializer) == typeof(JsonTypeSerializer) && JsState.WritingKeyCount > 0) { writer.Write(JsWriter.QuoteChar); } writer.Write(JsWriter.MapStartChar); var i = 0; if (WriteTypeInfo != null || JsState.IsWritingDynamic) { if (JsConfig.PreferInterfaces && TryWriteSelfType(writer)) { i++; } else if (TryWriteTypeInfo(writer, instance)) { i++; } JsState.IsWritingDynamic = false; } if (PropertyWriters != null) { var config = JsConfig <T> .GetConfig(); var typedInstance = (T)instance; var len = PropertyWriters.Length; for (int index = 0; index < len; index++) { var propertyWriter = PropertyWriters[index]; if (propertyWriter.shouldSerialize?.Invoke(typedInstance) == false) { continue; } var dontSkipDefault = false; if (propertyWriter.shouldSerializeDynamic != null) { var shouldSerialize = propertyWriter.shouldSerializeDynamic(typedInstance, propertyWriter.GetPropertyName(config)); if (shouldSerialize.HasValue) { if (shouldSerialize.Value) { dontSkipDefault = true; } else { continue; } } } var propertyValue = propertyWriter.GetterFn(typedInstance); if (!dontSkipDefault) { if (!propertyWriter.ShouldWriteProperty(propertyValue, config)) { continue; } if (config.ExcludePropertyReferences?.Contains(propertyWriter.propertyReferenceName) == true) { continue; } } if (i++ > 0) { writer.Write(JsWriter.ItemSeperator); } Serializer.WritePropertyName(writer, propertyWriter.GetPropertyName(config)); writer.Write(JsWriter.MapKeySeperator); if (typeof(TSerializer) == typeof(JsonTypeSerializer)) { JsState.IsWritingValue = true; } try { if (propertyValue == null) { writer.Write(JsonUtils.Null); } else { propertyWriter.WriteFn(writer, propertyValue); } } finally { if (typeof(TSerializer) == typeof(JsonTypeSerializer)) { JsState.IsWritingValue = false; } } } } writer.Write(JsWriter.MapEndChar); if (typeof(TSerializer) == typeof(JsonTypeSerializer) && JsState.WritingKeyCount > 0) { writer.Write(JsWriter.QuoteChar); } }