/// <summary> /// Deserializes the specified json string. /// </summary> /// <param name="json">The json.</param> /// <param name="currentReadIndex">Index of the current read.</param> /// <returns></returns> public override object Deserialize(string json, ref int currentReadIndex, SerializationContext context) { int startValueIndex = currentReadIndex + keyLength; int endValueIndex = json.IndexOfAny(Structure.EndValueChars, startValueIndex); currentReadIndex = endValueIndex; string stringValue = json.Substring(startValueIndex, endValueIndex - startValueIndex); if (isNullableType) { if (stringValue == Structure.NullValue) { return(null); } else { // reset start index currentReadIndex = startValueIndex - keyLength; return(nullableUnderlyingTypeConverter.Deserialize(json, ref currentReadIndex, context)); } } else { return(Convert.ChangeType(stringValue, type, CultureInfo.InvariantCulture)); } }
/// <summary> /// Deserializes the specified json. /// </summary> /// <param name="json">The json.</param> /// <param name="currentReadIndex">Index of the current read.</param> /// <param name="context"></param> /// <returns></returns> public override object Deserialize(string json, ref int currentReadIndex, SerializationContext context) { int startValueIndex = currentReadIndex + keyLength; //if (char.IsNumber(json[startValueIndex])) // string compatibility removed because of performance reasons //{ // Enum number value int enumNumberValue = (int)intEnumSerializer.Deserialize(json, ref currentReadIndex, context); return(Enum.ToObject(enumType, enumNumberValue)); //} //else //{ // // String enum representation // if (stringEnumSerializer == null) // stringEnumSerializer = Structure.DetermineStructure(typeof(int), this.key, null, this.isArrayItem); // string enumString = (string)stringEnumSerializer.Deserialize(json, ref currentReadIndex, context); // return Enum.Parse(enumType, enumString); //} }
/// <summary> /// Deserializes the specified json string. /// </summary> /// <param name="json">The json.</param> /// <param name="currentReadIndex">Index of the current read.</param> /// <param name="context">The context.</param> /// <returns></returns> public override object Deserialize(string json, ref int currentReadIndex, SerializationContext context) { // check if value is null int expectedSepIndex = currentReadIndex + keyLength; if (json[expectedSepIndex] == 'n' && json[expectedSepIndex + 1] == 'u' && json[expectedSepIndex + 2] == 'l' && json[expectedSepIndex + 3] == 'l') { currentReadIndex = expectedSepIndex + 4; return(null); } if (json[expectedSepIndex + 1] == Structure.CharQuotationMark && json[expectedSepIndex + 2] == '#' && json[expectedSepIndex + 3] == 't' && json[expectedSepIndex + 4] == 'y' && json[expectedSepIndex + 5] == 'p' && json[expectedSepIndex + 6] == 'e' ) { return(DeserializeSpecialType(json, ref currentReadIndex, context, expectedSepIndex)); } if (isObject) { Type objectTargetType = null; if (unknownTypeResolver != null) { context.Key = this.key; context.ValueStartIndex = currentReadIndex; context.ArrayIndex = null; context.JsonString = json; if (type.IsInterface) { context.InterfaceType = this.type; } objectTargetType = unknownTypeResolver(context); if (context.InterfaceType != null) { context.InterfaceType = null; } } if (objectTargetType == null) { objectTargetType = Structure.GetDefaultType(json, expectedSepIndex); if (objectTargetType == null) { throw new InvalidOperationException("Can't determine target type for JSON key: \"" + context.Key + "\""); } } IJsonTypeStructure currentObjectStructure; if (!typeSerializerCache.TryGetValue(objectTargetType, out currentObjectStructure)) { currentObjectStructure = Structure.DetermineStructure(objectTargetType, this.key, context, this.isArrayItem); typeSerializerCache[objectTargetType] = currentObjectStructure; } return(currentObjectStructure.Deserialize(json, ref currentReadIndex, context)); } else { if (json[currentReadIndex] != Structure.CharLeftBrace && !isArrayItem) { if (json[currentReadIndex] == Structure.CharComma) { currentReadIndex += 1; } expectedSepIndex = currentReadIndex + keyLength - 1; if (json[expectedSepIndex] == Structure.CharColon) { currentReadIndex = expectedSepIndex + 1; } else { throw new Exception("Unexpected JSON data!"); } } if (this.concreteTargetType == null) { // try get static target type if (type.IsInterface || type.IsAbstract) { context.InterfaceType = type; context.Key = key; Type itemTypeResolved = unknownTypeResolver(context); if (itemTypeResolved != null) { concreteTargetType = itemTypeResolved; } context.InterfaceType = null; } else { concreteTargetType = type; } } // create target object object target; try { target = TypeService.CreateInstance(this.concreteTargetType); } catch (Exception ex) { throw new Exception("Can't create object instance for \"" + this.concreteTargetType + "\" - \"" + type + "\"!", ex); } object oldParentObj = context.ParentObject; context.ParentObject = target; // jump over opening brace currentReadIndex += 1; for (int propIndex = 0; propIndex < objectStructure.Length; propIndex++) { IJsonTypeStructure structure = objectStructure[propIndex]; var setPropertyAccessor = setAccessorByPropertyIndex[propIndex]; // check out of order json int expectedKeyStartIndex = currentReadIndex + 1; int actualKeyIndex = json.IndexOf(structure.Key, expectedKeyStartIndex); if (actualKeyIndex != expectedKeyStartIndex || json[structure.Key.Length + actualKeyIndex] != Structure.CharQuotationMark) // Recognize key with the same begin string but different ending { // out of order key recognized int keyEndIndex = json.IndexOf(Structure.CharQuotationMark, expectedKeyStartIndex); int?keyStructureIndex = null; StructureComplexOutOfOrder cachedOutOfOrderStruct = null; string actualKey = null; if (keyEndIndex != -1) // ignore if end of json is reached { actualKey = json.Substring(expectedKeyStartIndex, keyEndIndex - expectedKeyStartIndex); // check if out of order structure is already cached if (outOfOrderStructures != null) { for (int indexCachedOutOfOrder = 0; indexCachedOutOfOrder < outOfOrderStructures.Count; indexCachedOutOfOrder++) { var cachedItem = outOfOrderStructures[indexCachedOutOfOrder]; if (cachedItem.ObjectStructure[propIndex].Key == actualKey) { cachedOutOfOrderStruct = cachedItem; break; } } } if (cachedOutOfOrderStruct == null) { // find out of order key keyStructureIndex = FindOutOfOrderKey(objectStructure, actualKey); } } if (cachedOutOfOrderStruct != null) { structure = cachedOutOfOrderStruct.ObjectStructure[propIndex]; setPropertyAccessor = cachedOutOfOrderStruct.SetAccessorByPropertyIndex[propIndex]; } else if (keyStructureIndex.HasValue) { lock (syncObj) { // create or move out of order structure if (outOfOrderStructures == null) { outOfOrderStructures = new List <StructureComplexOutOfOrder>(); } // try reuse existing out of order array StructureComplexOutOfOrder currentOutOfOrderStruct; var existing = outOfOrderStructures.Where(ooo => ooo.MaxTargetIndex < propIndex).FirstOrDefault(); IJsonTypeStructure[] sourceStructure = objectStructure; Func <object, object>[] sourceGetAccessorByPropertyIndex = getAccessorByPropertyIndex; Action <object, object>[] sourceSetAccessorByPropertyIndex = setAccessorByPropertyIndex; // create new cloned out of order strucutre if (existing == null) { currentOutOfOrderStruct = new StructureComplexOutOfOrder() { ObjectStructure = (IJsonTypeStructure[])sourceStructure.Clone(), GetAccessorByPropertyIndex = (Func <object, object>[])sourceGetAccessorByPropertyIndex.Clone(), SetAccessorByPropertyIndex = (Action <object, object>[])sourceSetAccessorByPropertyIndex.Clone() }; } else { currentOutOfOrderStruct = existing; sourceStructure = existing.ObjectStructure; structure = sourceStructure[propIndex]; sourceGetAccessorByPropertyIndex = existing.GetAccessorByPropertyIndex; sourceSetAccessorByPropertyIndex = existing.SetAccessorByPropertyIndex; // search in chached object structure again keyStructureIndex = FindOutOfOrderKey(sourceStructure, actualKey); } // switch object structure to received json order IJsonTypeStructure foundOutOfOrderStructure = sourceStructure[keyStructureIndex.Value]; currentOutOfOrderStruct.ObjectStructure[propIndex] = foundOutOfOrderStructure; currentOutOfOrderStruct.ObjectStructure[keyStructureIndex.Value] = structure; structure = foundOutOfOrderStructure; currentOutOfOrderStruct.MaxTargetIndex = propIndex; // switch value setter var currentAccessor = sourceGetAccessorByPropertyIndex[propIndex]; var foundOutOfOrderAccessor = sourceGetAccessorByPropertyIndex[keyStructureIndex.Value]; currentOutOfOrderStruct.GetAccessorByPropertyIndex[propIndex] = foundOutOfOrderAccessor; currentOutOfOrderStruct.GetAccessorByPropertyIndex[keyStructureIndex.Value] = currentAccessor; var currentAccessorSet = sourceSetAccessorByPropertyIndex[propIndex]; var foundOutOfOrderAccessorSet = sourceSetAccessorByPropertyIndex[keyStructureIndex.Value]; currentOutOfOrderStruct.SetAccessorByPropertyIndex[propIndex] = foundOutOfOrderAccessorSet; currentOutOfOrderStruct.SetAccessorByPropertyIndex[keyStructureIndex.Value] = currentAccessorSet; setPropertyAccessor = foundOutOfOrderAccessorSet; if (existing == null) { outOfOrderStructures.Add(currentOutOfOrderStruct); } } } else { if (context.Serializer.IsMissingFieldDataAllowed) { if (SkipJsonElement(json, ref currentReadIndex)) { propIndex--; // re-read current structure } continue; // ignore missing field } else { throw new KeyNotFoundException(string.Format("The key: \"{0}\" is not present in the object structure! JSON: \"{1}\"; Target Type: \"{2}\"", actualKey, json, this.type.AssemblyQualifiedName)); } } } object value = structure.Deserialize(json, ref currentReadIndex, context); if (value != null) { setPropertyAccessor(target, value); } if (json[currentReadIndex] == Structure.CharRightBrace) { // end reached currentReadIndex++; break; } currentReadIndex++; } if (json[currentReadIndex - 1] != Structure.CharRightBrace) { if (context.Serializer.IsMissingFieldDataAllowed) { // json object contains more data than expected from the type structure // skip futher object data SkipJsonObject(json, ref currentReadIndex); } else { throw new InvalidOperationException(string.Format("The json object contains more data than expected in target type! JSON: \"{0}\"; Key: \"{1}\"; Target Type: \"{2}\"", json, this.key, this.type.AssemblyQualifiedName)); } } context.ParentObject = oldParentObj; return(target); } }
private object DeserializeArrayItem(string json, ref int currentReadIndex, int arrayItemIndex, SerializationContext context) { if (json[currentReadIndex] == 'n' && json[currentReadIndex + 1] == 'u' && json[currentReadIndex + 2] == 'l' && json[currentReadIndex + 3] == 'l') { currentReadIndex = currentReadIndex + 4; return(null); } //Type objectTargetType = null; if (json[currentReadIndex + 2] == '#' && json[currentReadIndex + 3] == 't' && json[currentReadIndex + 4] == 'y' && json[currentReadIndex + 5] == 'p' && json[currentReadIndex + 6] == 'e' ) { return(DeserializeSpecialType(json, ref currentReadIndex, context, currentReadIndex)); } object itemValue; if (this.isObject) { // determine target type during deserialization Type type = null; if (unknownTypeResolver != null) { context.Key = this.key; context.ValueStartIndex = currentReadIndex; context.ArrayIndex = arrayItemIndex; context.JsonString = json; type = unknownTypeResolver(context); context.ArrayIndex = null; } if (type == null || type.Equals(typeof(object))) { type = Structure.GetDefaultType(json, currentReadIndex); if (type == null) { int readCount = Math.Min(json.Length - currentReadIndex, 25); string jsonPart = json.Substring(currentReadIndex, readCount); throw new InvalidOperationException(string.Format("Unable to get the target type for array object index {0}; Key: {1}; JSON part: \"{2}\"", arrayItemIndex, this.key, jsonPart)); } } IJsonTypeStructure currentObjectStructure; if (!typeSerializerCache.TryGetValue(type, out currentObjectStructure)) { currentObjectStructure = Structure.DetermineStructure(type, GetNestedArrayKey(this.key, arrayItemIndex), context, true); typeSerializerCache[type] = currentObjectStructure; } itemValue = currentObjectStructure.Deserialize(json, ref currentReadIndex, context); } else { if (itemDeSerializer == null) { itemDeSerializer = Structure.DetermineStructure(itemType, key, context, true); } // fixed array target type itemValue = itemDeSerializer.Deserialize(json, ref currentReadIndex, context); } return(itemValue); }