public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { object list; if (DocumentRootConverter.TryResolveAsRootData(reader, objectType, serializer, out list)) { return(list); } //read into the 'Data' path var preDataPath = ReaderUtil.ReadUntilStart(reader, DataPathRegex); //we should be dealing with list types, but we also want the element type Type elementType; if (!ListUtil.IsList(objectType, out elementType)) { throw new ArgumentException($"{typeof(ResourceObjectListConverter)} can only read json lists", nameof(objectType)); } var itemsIterator = ReaderUtil.IterateList(reader).Select(x => serializer.Deserialize(reader, elementType)); list = ListUtil.CreateList(objectType, itemsIterator); //read out of the 'Data' path ReaderUtil.ReadUntilEnd(reader, preDataPath); return(list); }
private object ReadJsonAsResourceObject(ForkableJsonReader reader, Type objectType, JsonSerializer serializer) { // if the value has been explicitly set to null then the value of the element is simply null if (reader.TokenType == JsonToken.Null) { return(null); } var serializationData = SerializationData.GetSerializationData(reader); var jsonApiContractResolver = (JsonApiContractResolver)serializer.ContractResolver; var reference = ReaderUtil.ReadAheadToIdentifyObject(reader); if (serializationData.Included.TryGetValue(reference, out object resourceObject)) { if (resourceObject is JObject resoruceObjectJObject) { // sometimes the value in the reference resolver is a JObject. This occurs when we // did not know what type it should be when we first read it (i.e. included was processed // before the item). In these cases we now know what type it should be so will read it // as such var resourceObjectReader = new ForkableJsonReader(resoruceObjectJObject.CreateReader(), reader.SerializationDataToken); resourceObjectReader.Read(); //JObject readers begin at Not Started resourceObject = jsonApiContractResolver.ResourceObjectConverter.ReadJson( resourceObjectReader, objectType, null, serializer); } //push the reader to the end, we dont need anything else out of the reference ReaderUtil.ReadUntilEnd(reader, reader.Path); } else { var contract = (JsonObjectContract)jsonApiContractResolver.ResolveContract(objectType); resourceObject = ReaderUtil.CreateObject(serializationData, objectType, reference.Type, serializer); // for placeholders we will just read the top level properties // it is unlikely to have attributes/relationships present foreach (var propName in ReaderUtil.IterateProperties(reader)) { var successfullyPopulateProperty = ReaderUtil.TryPopulateProperty( serializer, resourceObject, contract.Properties.GetClosestMatchProperty(propName), reader); } serializationData.Included[reference] = resourceObject; } if (!TypeInfoShim.IsInstanceOf(objectType.GetTypeInfo(), resourceObject)) { throw new JsonSerializationException($"Unable to assign object '{resourceObject}' to type '{objectType}' at path {reader.FullPath}"); } return(resourceObject); }
protected object PopulateProperties(JsonSerializer serializer, object obj, JsonReader reader, JsonObjectContract contract) { foreach (var propName in ReaderUtil.IterateProperties(reader)) { if (propName == PropertyNames.Type) { var type = reader.Value; if (obj.GetType().Name.ToLower() != type.ToString().ToLower()) { Assembly[] assembly = Utility.GetAssemblies(); var tp = assembly.SelectMany(s => s.GetTypes()).ToList().Where(t => t.Name.ToLower() == type.ToString().ToLower()).SingleOrDefault(); if (tp != null) { obj = Activator.CreateInstance(tp); contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(obj.GetType()); } } //retObj.id = obj; } var successfullyPopulateProperty = ReaderUtil.TryPopulateProperty( serializer, obj, contract.Properties.GetClosestMatchProperty(propName), reader); if (!successfullyPopulateProperty) { //flatten out attributes onto the object if (propName == "attributes") { foreach (var innerPropName in ReaderUtil.IterateProperties(reader)) { ReaderUtil.TryPopulateProperty( serializer, obj, contract.Properties.GetClosestMatchProperty(innerPropName), reader); } } //flatten out relationships onto the object if (propName == "relationships") { foreach (var innerPropName in ReaderUtil.IterateProperties(reader)) { //read into the 'Data' path var preDataPath = ReaderUtil.ReadUntilStart(reader, DataPathRegex); ReaderUtil.TryPopulateProperty( serializer, obj, contract.Properties.GetClosestMatchProperty(innerPropName), reader); //read out of the 'Data' path ReaderUtil.ReadUntilEnd(reader, preDataPath); } } } } return(obj); }