/// <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); } }
public bool TryGetExport(Type type, Type injectTargetType, List <Type> pendingCreateList, out object instance) { if (discoveryConditionItems != null) { DiscoveryContext ctx = new DiscoveryContext(type, injectTargetType); foreach (var cond in discoveryConditionItems) { if (cond.IsMatching(ctx)) { return(cond.TargetContainer.TryGetExport(type, injectTargetType, out instance)); } } } if (localShare.SharedLocalInstances.TryGetValue(type, out instance)) { return(true); } if (hostSessionsSharedInstances.TryGetValue(type, out instance)) { return(true); } Type targetType; var contract = currentContract; if (type.IsInterface) { if (contract != null) { if (contract.TryGetSessionInstance(type, out instance)) { return(true); } } if (!localShare.TryFindInterfaceImplementation(type, injectTargetType, out targetType)) { // not found > check if multiple import if (type.GetInterface(typeof(System.Collections.IEnumerable).FullName) != null) { var multiImportColl = localShare.CollectLocalMultiImports(this, type, injectTargetType, pendingCreateList); if (multiImportColl != null) { instance = multiImportColl; return(true); } } else { instance = null; return(false); } } } else if (type.IsArray) { var multiImportColl = this.localShare.CollectLocalMultiImports(this, type, injectTargetType, pendingCreateList); if (multiImportColl != null) { instance = multiImportColl; return(true); } else { instance = null; return(false); } } else { targetType = type; } object[] outParams; ParameterInfo[] outParamsInfo; instance = TypeService.CreateInstance(targetType, DetermineConstructorImportInstance, pendingCreateList, out outParams, out outParamsInfo); localShare.CheckOutParamsSubscriptions(instance, outParams, this, type); localShare.RegisterSharedConstructorInstances(type, instance, outParams, outParamsInfo); if (contract != null && this.localSessionServiceInterfaceTypesResolved.Contains(type)) { // update contract service cache here as well to be not dependent on the registration order in nested cases int cachedAtIndex = Array.IndexOf <Type>(this.localSessionServiceInterfaceTypesResolved, type); contract.LocalServices[cachedAtIndex] = instance; } //todo: parent container handling return(true); }
internal IEnumerable CollectLocalMultiImports(TalkCompositionHost host, Type type, Type injectTargetType, List <Type> pendingCreateList) { // multiple imports // 1. determine generic target interface type // 2. create concreate target collection instance // 3. add one instance of all local implementations Type genericCollectionInterface = type.GetInterface("IEnumerable`1"); if (type.IsGenericType || genericCollectionInterface != null) { Type enumerableClassType = null; Type[] genericTypes = type.GetGenericArguments(); if (genericTypes.Length == 1) { Type listType = typeof(List <>); enumerableClassType = listType.MakeGenericType(genericTypes); } else if (genericTypes.Length == 0 && genericCollectionInterface != null) { genericTypes = genericCollectionInterface.GetGenericArguments(); Type listType = typeof(List <>); enumerableClassType = listType.MakeGenericType(genericTypes); } if (enumerableClassType != null && genericTypes.Length == 1) { Type targetInterfaceType = genericTypes[0]; bool isShared = IsMultiShared(targetInterfaceType); IList targetCollection = null; if (isShared) { targetCollection = GetLocalSharedMultipleInstances(targetInterfaceType); } if (targetCollection == null) { targetCollection = (IList)TypeService.CreateInstance(enumerableClassType); // create new instances HashSet <Type> createdTypes = new HashSet <Type>(); foreach (Type implType in this.FindInterfaceImplementations(targetInterfaceType, injectTargetType)) { if (!createdTypes.Contains(implType) && injectTargetType != implType) { object[] outParams; ParameterInfo[] outParamsInfo; object itemInstance; if (host != null) { itemInstance = TypeService.CreateInstance(implType, host.DetermineConstructorImportInstance, pendingCreateList, out outParams, out outParamsInfo); } else { itemInstance = TypeService.CreateInstance(implType, this.DetermineConstructorImportInstance, pendingCreateList, out outParams, out outParamsInfo); } CheckOutParamsSubscriptions(itemInstance, outParams, host, targetInterfaceType); targetCollection.Add(itemInstance); RegisterSharedConstructorInstances(targetInterfaceType, itemInstance, outParams, outParamsInfo); createdTypes.Add(implType); } } if (isShared) { if (localSharedMultipleInterfaceInstances == null) { localSharedMultipleInterfaceInstances = new Dictionary <Type, IList>(); } // add to shared dictionary localSharedMultipleInterfaceInstances.Add(targetInterfaceType, targetCollection); } } if (type.IsArray) { Type arrayItemType = type.GetElementType(); Array targetArray = Array.CreateInstance(arrayItemType, targetCollection.Count); for (int i = 0; i < targetCollection.Count; i++) { targetArray.SetValue(targetCollection[i], i); } return(targetArray); } else { return(targetCollection); } } } return(null); }
public bool TryGetExport(Type type, Type injectTargetType, List <Type> pendingCreateList, out object instance) { if (discoveryConditionItems != null) { DiscoveryContext ctx = new DiscoveryContext(type, injectTargetType); foreach (var cond in discoveryConditionItems) { if (cond.IsMatching(ctx)) { return(cond.TargetContainer.TryGetExport(type, injectTargetType, out instance)); } } } if (this.SharedLocalInstances.TryGetValue(type, out instance)) { return(true); } //if (hostSessionsSharedInstances.TryGetValue(type, out instance)) //{ // return true; //} if (ParentContainer != null && ParentContainer is IContainerSharedByType parentShared && parentShared.TryGetCachedLocalExport(type, out instance)) { return(true); } // create new instance Type targetType; if (type.IsInterface) { //var contract = currentContract; //if (contract != null) //{ // if (contract.TryGetSessionInstance(type, out instance)) // { // return true; // } //} if (!TryFindInterfaceImplementation(type, injectTargetType, out targetType)) { // not found > check if multiple import if (type.GetInterface(typeof(System.Collections.IEnumerable).FullName) != null) { var multiImportColl = this.CollectLocalMultiImports(null, type, injectTargetType, pendingCreateList); if (multiImportColl != null) { instance = multiImportColl; return(true); } // todo: else? } else { instance = null; return(false); } } } else if (type.IsArray) { var multiImportColl = this.CollectLocalMultiImports(null, type, injectTargetType, pendingCreateList); if (multiImportColl != null) { instance = multiImportColl; return(true); } else { instance = null; return(false); } } else { targetType = type; } object[] outParams; ParameterInfo[] outParamsInfo; instance = TypeService.CreateInstance(targetType, DetermineConstructorImportInstance, pendingCreateList, out outParams, out outParamsInfo); this.CheckOutParamsSubscriptions(instance, outParams, null, type); this.RegisterSharedConstructorInstances(type, instance, outParams, outParamsInfo); return(true); }
public object ReadValue(IStreamReader reader, ISerializeContext context, bool isReadTypeIdExpected) { context.Key = this.Name; context.ArrayIndex = null; if (isReadTypeIdExpected) { // read type of property uint actualTypeId = reader.ReadUInt32(); if (TypeId != actualTypeId) { if (actualTypeId == (int)ItemType.ComplexObject) { // Special read > only null expected byte contentObjType = reader.ReadUInt8(); if (contentObjType == ValueItem.NullValueIdent) { return(null); } else { throw new ArgumentException("ComplexObject type ID is only expected with null!"); } } var actualStructure = context.GetByTypeId(actualTypeId); if (actualStructure == null) { // type not in local cache > type meta info exptected actualStructure = TypeMetaStructure.ReadContentTypeMetaInfo(reader, actualTypeId, context); } if (actualStructure.IsTypePrefixExpected) { if (actualStructure is ITypePrefix) { // type id already consumed > do not read again return(((ITypePrefix)actualStructure).ReadValue(reader, context, false)); } else { return(actualStructure.ReadValue(reader, context)); } } else { // read content type because of unknown strucutre byte contentObjType = reader.ReadUInt8(); if (contentObjType == ValueItem.NullValueIdent) { return(null); } else { return(actualStructure.ReadValue(reader, context)); } } } } byte contentType = reader.ReadUInt8(); if (contentType == ValueItem.TypeMetaInfo) { // type meta data already loaded for type id > skip data TypeMetaStructure.SkipTypeMetaInfo(reader); contentType = reader.ReadUInt8(); } switch (contentType) { case ValueItem.SingleObjectIdent: object newObject = TypeService.CreateInstance(concreteTargetType); object oldParentObj = context.ParentObject; context.ParentObject = newObject; for (int itemIndex = 0; itemIndex < items.Count; itemIndex++) { var item = items[itemIndex]; var itemValue = item.ReadValue(reader, context); item.SetItemValue(newObject, itemValue); } context.ParentObject = oldParentObj; return(newObject); case ValueItem.NullValueIdent: return(null); case ValueItem.CollectionObjectIdent: throw new NotImplementedException(); default: throw new InvalidOperationException($"Type ident {contentType} not expected!"); } }
/// <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) { currentReadIndex = currentReadIndex + keyLength; if (json[currentReadIndex] == Structure.CharLeftSquareBrace) { currentReadIndex++; if (type.IsArray) { ArrayList soureList = new ArrayList(); while (true) { if (json[currentReadIndex] == Structure.CharRightSquareBracet) { // is empty array currentReadIndex += 1; break; } object itemValue = DeserializeArrayItem(json, ref currentReadIndex, soureList.Count, context); soureList.Add(itemValue); if (json[currentReadIndex] == Structure.CharRightSquareBracet) { currentReadIndex += 1; break; } currentReadIndex += 1; } // copy items to target array Array targetValueArray = Array.CreateInstance(itemType, soureList.Count); for (int i = 0; i < soureList.Count; i++) { targetValueArray.SetValue(soureList[i], i); } return(targetValueArray); } else { object targetCollectionObj = TypeService.CreateInstance(targetCollectionType); if (targetCollectionObj is IList) { IList targetCollection = (IList)targetCollectionObj; while (true) { if (json[currentReadIndex] == Structure.CharRightSquareBracet) { // is empty array currentReadIndex += 1; break; } object itemValue = DeserializeArrayItem(json, ref currentReadIndex, targetCollection.Count, context); targetCollection.Add(itemValue); if (json[currentReadIndex] == Structure.CharRightSquareBracet) { currentReadIndex += 1; break; } currentReadIndex += 1; } return(targetCollection); } else { // collection does not implement IList // Unable to cast to ICollection<T> // try to get Add method using reflection MethodInfo miAdd; if (specialCollectionTypeAddMethodCache == null || !specialCollectionTypeAddMethodCache.TryGetValue(targetCollectionType, out miAdd)) { miAdd = targetCollectionType.GetMethod("Add"); if (miAdd != null) { specialCollectionTypeAddMethodCache = new ConcurrentDictionary <Type, MethodInfo>(); specialCollectionTypeAddMethodCache.TryAdd(targetCollectionType, miAdd); } else { throw new InvalidCastException("The collection type " + targetCollectionType.FullName + " is not supported! Unable to get items \"Add\" method."); } } int count = 0; while (true) { if (json[currentReadIndex] == Structure.CharRightSquareBracet) { // is empty array currentReadIndex += 1; break; } object itemValue = DeserializeArrayItem(json, ref currentReadIndex, count, context); miAdd.Invoke(targetCollectionObj, new object[] { itemValue }); if (json[currentReadIndex] == Structure.CharRightSquareBracet) { currentReadIndex += 1; break; } currentReadIndex += 1; count++; } return(targetCollectionObj); } } } else if (json[currentReadIndex] == Structure.CharQuotationMark && isByteArray) { // Byte array base64 encoding optimization currentReadIndex++; int endDataIndex = json.IndexOf(Structure.CharQuotationMark, currentReadIndex); if (endDataIndex > 0) { int length = endDataIndex - currentReadIndex; string base64Data = json.Substring(currentReadIndex, length); byte[] data = Convert.FromBase64String(base64Data); currentReadIndex += length + 1; return(data); } else { throw new InvalidCastException("No end quotation mark for base64 encoding found!"); } } else if (json[currentReadIndex] == 'n' && json[currentReadIndex + 1] == 'u' && json[currentReadIndex + 2] == 'l' && json[currentReadIndex + 3] == 'l') { currentReadIndex += 4; return(null); } else { throw new NotImplementedException(); } }
public object ReadValue(IStreamReader reader, ISerializeContext context) { byte contentType = reader.ReadUInt8(); context.Key = this.Name; if (contentType == ValueItem.CollectionObjectIdent) { int count = reader.ReadInt32(); if (isArray) { Array array = Array.CreateInstance(itemType, count); if (isByteArray) { return(reader.ReadBytes(count).ToArray()); } else { for (int i = 0; i < count; i++) { context.ArrayIndex = i; var item = itemStructure.ReadValue(reader, context); array.SetValue(item, i); } context.ArrayIndex = null; } return(array); } else if (implementsIList) { IList coll = (IList)TypeService.CreateInstance(targetCollectionType); for (int i = 0; i < count; i++) { context.ArrayIndex = i; var item = itemStructure.ReadValue(reader, context); coll.Add(item); } context.ArrayIndex = null; return(coll); } else { object specialColl = TypeService.CreateInstance(targetCollectionType); for (int i = 0; i < count; i++) { context.ArrayIndex = i; var item = itemStructure.ReadValue(reader, context); specialCollAddMethod.Invoke(specialColl, new object[] { item }); } context.ArrayIndex = null; return(specialColl); } } else if (contentType == ValueItem.NullValueIdent) { return(null); } else if (contentType == ValueItem.TypeMetaInfo) { TypeMetaStructure.SkipTypeMetaInfo(reader); return(this.ReadValue(reader, context)); } else { throw new InvalidOperationException($"Type ident {contentType} not expected!"); } }