You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2548 lines
114 KiB

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections;
  27. using System.Collections.Generic;
  28. using System.Collections.ObjectModel;
  29. #if !NET20
  30. using System.ComponentModel;
  31. using System.Dynamic;
  32. #endif
  33. using System.Diagnostics;
  34. using System.Globalization;
  35. #if HAVE_BIG_INTEGER
  36. using System.Numerics;
  37. #endif
  38. using System.Reflection;
  39. using System.Runtime.Serialization;
  40. using Newtonsoft.Json.Linq;
  41. using Newtonsoft.Json.Utilities;
  42. #if NET20
  43. using Newtonsoft.Json.Utilities.LinqBridge;
  44. #else
  45. using System.Linq;
  46. #endif
  47. namespace Newtonsoft.Json.Serialization
  48. {
  49. internal class JsonSerializerInternalReader : JsonSerializerInternalBase
  50. {
  51. internal enum PropertyPresence
  52. {
  53. None = 0,
  54. Null = 1,
  55. Value = 2
  56. }
  57. public JsonSerializerInternalReader(JsonSerializer serializer)
  58. : base(serializer)
  59. {
  60. }
  61. public void Populate(JsonReader reader, object target)
  62. {
  63. ValidationUtils.ArgumentNotNull(target, nameof(target));
  64. Type objectType = target.GetType();
  65. JsonContract contract = Serializer._contractResolver.ResolveContract(objectType);
  66. if (!reader.MoveToContent())
  67. {
  68. throw JsonSerializationException.Create(reader, "No JSON content found.");
  69. }
  70. if (reader.TokenType == JsonToken.StartArray)
  71. {
  72. if (contract.ContractType == JsonContractType.Array)
  73. {
  74. JsonArrayContract arrayContract = (JsonArrayContract)contract;
  75. PopulateList((arrayContract.ShouldCreateWrapper) ? arrayContract.CreateWrapper(target) : (IList)target, reader, arrayContract, null, null);
  76. }
  77. else
  78. {
  79. throw JsonSerializationException.Create(reader, "Cannot populate JSON array onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
  80. }
  81. }
  82. else if (reader.TokenType == JsonToken.StartObject)
  83. {
  84. reader.ReadAndAssert();
  85. string id = null;
  86. if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore
  87. && reader.TokenType == JsonToken.PropertyName
  88. && string.Equals(reader.Value.ToString(), JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
  89. {
  90. reader.ReadAndAssert();
  91. id = reader.Value?.ToString();
  92. reader.ReadAndAssert();
  93. }
  94. if (contract.ContractType == JsonContractType.Dictionary)
  95. {
  96. JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)contract;
  97. PopulateDictionary((dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(target) : (IDictionary)target, reader, dictionaryContract, null, id);
  98. }
  99. else if (contract.ContractType == JsonContractType.Object)
  100. {
  101. PopulateObject(target, reader, (JsonObjectContract)contract, null, id);
  102. }
  103. else
  104. {
  105. throw JsonSerializationException.Create(reader, "Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
  106. }
  107. }
  108. else
  109. {
  110. throw JsonSerializationException.Create(reader, "Unexpected initial token '{0}' when populating object. Expected JSON object or array.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
  111. }
  112. }
  113. private JsonContract GetContractSafe(Type type)
  114. {
  115. if (type == null)
  116. {
  117. return null;
  118. }
  119. return Serializer._contractResolver.ResolveContract(type);
  120. }
  121. public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
  122. {
  123. if (reader == null)
  124. {
  125. throw new ArgumentNullException(nameof(reader));
  126. }
  127. JsonContract contract = GetContractSafe(objectType);
  128. try
  129. {
  130. JsonConverter converter = GetConverter(contract, null, null, null);
  131. if (reader.TokenType == JsonToken.None && !reader.ReadForType(contract, converter != null))
  132. {
  133. if (contract != null && !contract.IsNullable)
  134. {
  135. throw JsonSerializationException.Create(reader, "No JSON content found and type '{0}' is not nullable.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  136. }
  137. return null;
  138. }
  139. object deserializedValue;
  140. if (converter != null && converter.CanRead)
  141. {
  142. deserializedValue = DeserializeConvertable(converter, reader, objectType, null);
  143. }
  144. else
  145. {
  146. deserializedValue = CreateValueInternal(reader, objectType, contract, null, null, null, null);
  147. }
  148. if (checkAdditionalContent)
  149. {
  150. while (reader.Read())
  151. {
  152. if (reader.TokenType != JsonToken.Comment)
  153. {
  154. throw JsonSerializationException.Create(reader, "Additional text found in JSON string after finishing deserializing object.");
  155. }
  156. }
  157. }
  158. return deserializedValue;
  159. }
  160. catch (Exception ex)
  161. {
  162. if (IsErrorHandled(null, contract, null, reader as IJsonLineInfo, reader.Path, ex))
  163. {
  164. HandleError(reader, false, 0);
  165. return null;
  166. }
  167. else
  168. {
  169. // clear context in case serializer is being used inside a converter
  170. // if the converter wraps the error then not clearing the context will cause this error:
  171. // "Current error context error is different to requested error."
  172. ClearErrorContext();
  173. throw;
  174. }
  175. }
  176. }
  177. private JsonSerializerProxy GetInternalSerializer()
  178. {
  179. if (InternalSerializer == null)
  180. {
  181. InternalSerializer = new JsonSerializerProxy(this);
  182. }
  183. return InternalSerializer;
  184. }
  185. private JToken CreateJToken(JsonReader reader, JsonContract contract)
  186. {
  187. ValidationUtils.ArgumentNotNull(reader, nameof(reader));
  188. if (contract != null)
  189. {
  190. if (contract.UnderlyingType == typeof(JRaw))
  191. {
  192. return JRaw.Create(reader);
  193. }
  194. if (reader.TokenType == JsonToken.Null
  195. && !(contract.UnderlyingType == typeof(JValue) || contract.UnderlyingType == typeof(JToken)))
  196. {
  197. return null;
  198. }
  199. }
  200. JToken token;
  201. using (JTokenWriter writer = new JTokenWriter())
  202. {
  203. writer.WriteToken(reader);
  204. token = writer.Token;
  205. }
  206. return token;
  207. }
  208. private JToken CreateJObject(JsonReader reader)
  209. {
  210. ValidationUtils.ArgumentNotNull(reader, nameof(reader));
  211. // this is needed because we've already read inside the object, looking for metadata properties
  212. using (JTokenWriter writer = new JTokenWriter())
  213. {
  214. writer.WriteStartObject();
  215. do
  216. {
  217. if (reader.TokenType == JsonToken.PropertyName)
  218. {
  219. string propertyName = (string)reader.Value;
  220. if (!reader.ReadAndMoveToContent())
  221. {
  222. break;
  223. }
  224. if (CheckPropertyName(reader, propertyName))
  225. {
  226. continue;
  227. }
  228. writer.WritePropertyName(propertyName);
  229. writer.WriteToken(reader, true, true, false);
  230. }
  231. else if (reader.TokenType == JsonToken.Comment)
  232. {
  233. // eat
  234. }
  235. else
  236. {
  237. writer.WriteEndObject();
  238. return writer.Token;
  239. }
  240. } while (reader.Read());
  241. throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
  242. }
  243. }
  244. private object CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
  245. {
  246. if (contract != null && contract.ContractType == JsonContractType.Linq)
  247. {
  248. return CreateJToken(reader, contract);
  249. }
  250. do
  251. {
  252. switch (reader.TokenType)
  253. {
  254. // populate a typed object or generic dictionary/array
  255. // depending upon whether an objectType was supplied
  256. case JsonToken.StartObject:
  257. return CreateObject(reader, objectType, contract, member, containerContract, containerMember, existingValue);
  258. case JsonToken.StartArray:
  259. return CreateList(reader, objectType, contract, member, existingValue, null);
  260. case JsonToken.Integer:
  261. case JsonToken.Float:
  262. case JsonToken.Boolean:
  263. case JsonToken.Date:
  264. case JsonToken.Bytes:
  265. return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
  266. case JsonToken.String:
  267. string s = (string)reader.Value;
  268. // convert empty string to null automatically for nullable types
  269. if (CoerceEmptyStringToNull(objectType, contract, s))
  270. {
  271. return null;
  272. }
  273. // string that needs to be returned as a byte array should be base 64 decoded
  274. if (objectType == typeof(byte[]))
  275. {
  276. return Convert.FromBase64String(s);
  277. }
  278. return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType);
  279. case JsonToken.StartConstructor:
  280. string constructorName = reader.Value.ToString();
  281. return EnsureType(reader, constructorName, CultureInfo.InvariantCulture, contract, objectType);
  282. case JsonToken.Null:
  283. case JsonToken.Undefined:
  284. #if HAVE_ADO_NET
  285. if (objectType == typeof(DBNull))
  286. {
  287. return DBNull.Value;
  288. }
  289. #endif
  290. return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
  291. case JsonToken.Raw:
  292. return new JRaw((string)reader.Value);
  293. case JsonToken.Comment:
  294. // ignore
  295. break;
  296. default:
  297. throw JsonSerializationException.Create(reader, "Unexpected token while deserializing object: " + reader.TokenType);
  298. }
  299. } while (reader.Read());
  300. throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
  301. }
  302. private static bool CoerceEmptyStringToNull(Type objectType, JsonContract contract, string s)
  303. {
  304. return string.IsNullOrEmpty(s) && objectType != null && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable;
  305. }
  306. internal string GetExpectedDescription(JsonContract contract)
  307. {
  308. switch (contract.ContractType)
  309. {
  310. case JsonContractType.Object:
  311. case JsonContractType.Dictionary:
  312. #if HAVE_BINARY_SERIALIZATION
  313. case JsonContractType.Serializable:
  314. #endif
  315. #if !NET20
  316. case JsonContractType.Dynamic:
  317. #endif
  318. return @"JSON object (e.g. {""name"":""value""})";
  319. case JsonContractType.Array:
  320. return @"JSON array (e.g. [1,2,3])";
  321. case JsonContractType.Primitive:
  322. return @"JSON primitive value (e.g. string, number, boolean, null)";
  323. case JsonContractType.String:
  324. return @"JSON string value";
  325. default:
  326. throw new ArgumentOutOfRangeException();
  327. }
  328. }
  329. private JsonConverter GetConverter(JsonContract contract, JsonConverter memberConverter, JsonContainerContract containerContract, JsonProperty containerProperty)
  330. {
  331. JsonConverter converter = null;
  332. if (memberConverter != null)
  333. {
  334. // member attribute converter
  335. converter = memberConverter;
  336. }
  337. else if (containerProperty?.ItemConverter != null)
  338. {
  339. converter = containerProperty.ItemConverter;
  340. }
  341. else if (containerContract?.ItemConverter != null)
  342. {
  343. converter = containerContract.ItemConverter;
  344. }
  345. else if (contract != null)
  346. {
  347. JsonConverter matchingConverter;
  348. if (contract.Converter != null)
  349. {
  350. // class attribute converter
  351. converter = contract.Converter;
  352. }
  353. else if ((matchingConverter = Serializer.GetMatchingConverter(contract.UnderlyingType)) != null)
  354. {
  355. // passed in converters
  356. converter = matchingConverter;
  357. }
  358. else if (contract.InternalConverter != null)
  359. {
  360. // internally specified converter
  361. converter = contract.InternalConverter;
  362. }
  363. }
  364. return converter;
  365. }
  366. private object CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue)
  367. {
  368. string id;
  369. Type resolvedObjectType = objectType;
  370. if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.Ignore)
  371. {
  372. // don't look for metadata properties
  373. reader.ReadAndAssert();
  374. id = null;
  375. }
  376. else if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead)
  377. {
  378. if (!(reader is JTokenReader tokenReader))
  379. {
  380. JToken t = JToken.ReadFrom(reader);
  381. tokenReader = (JTokenReader)t.CreateReader();
  382. tokenReader.Culture = reader.Culture;
  383. tokenReader.DateFormatString = reader.DateFormatString;
  384. tokenReader.DateParseHandling = reader.DateParseHandling;
  385. tokenReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
  386. tokenReader.FloatParseHandling = reader.FloatParseHandling;
  387. tokenReader.SupportMultipleContent = reader.SupportMultipleContent;
  388. // start
  389. tokenReader.ReadAndAssert();
  390. reader = tokenReader;
  391. }
  392. if (ReadMetadataPropertiesToken(tokenReader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id))
  393. {
  394. return newValue;
  395. }
  396. }
  397. else
  398. {
  399. reader.ReadAndAssert();
  400. if (ReadMetadataProperties(reader, ref resolvedObjectType, ref contract, member, containerContract, containerMember, existingValue, out object newValue, out id))
  401. {
  402. return newValue;
  403. }
  404. }
  405. if (HasNoDefinedType(contract))
  406. {
  407. return CreateJObject(reader);
  408. }
  409. switch (contract.ContractType)
  410. {
  411. case JsonContractType.Object:
  412. {
  413. bool createdFromNonDefaultCreator = false;
  414. JsonObjectContract objectContract = (JsonObjectContract)contract;
  415. object targetObject;
  416. // check that if type name handling is being used that the existing value is compatible with the specified type
  417. if (existingValue != null && (resolvedObjectType == objectType || resolvedObjectType.IsAssignableFrom(existingValue.GetType())))
  418. {
  419. targetObject = existingValue;
  420. }
  421. else
  422. {
  423. targetObject = CreateNewObject(reader, objectContract, member, containerMember, id, out createdFromNonDefaultCreator);
  424. }
  425. // don't populate if read from non-default creator because the object has already been read
  426. if (createdFromNonDefaultCreator)
  427. {
  428. return targetObject;
  429. }
  430. return PopulateObject(targetObject, reader, objectContract, member, id);
  431. }
  432. case JsonContractType.Primitive:
  433. {
  434. JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
  435. // if the content is inside $value then read past it
  436. if (Serializer.MetadataPropertyHandling != MetadataPropertyHandling.Ignore
  437. && reader.TokenType == JsonToken.PropertyName
  438. && string.Equals(reader.Value.ToString(), JsonTypeReflector.ValuePropertyName, StringComparison.Ordinal))
  439. {
  440. reader.ReadAndAssert();
  441. // the token should not be an object because the $type value could have been included in the object
  442. // without needing the $value property
  443. if (reader.TokenType == JsonToken.StartObject)
  444. {
  445. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing primitive value: " + reader.TokenType);
  446. }
  447. object value = CreateValueInternal(reader, resolvedObjectType, primitiveContract, member, null, null, existingValue);
  448. reader.ReadAndAssert();
  449. return value;
  450. }
  451. break;
  452. }
  453. case JsonContractType.Dictionary:
  454. {
  455. JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)contract;
  456. object targetDictionary;
  457. if (existingValue == null)
  458. {
  459. IDictionary dictionary = CreateNewDictionary(reader, dictionaryContract, out bool createdFromNonDefaultCreator);
  460. if (createdFromNonDefaultCreator)
  461. {
  462. if (id != null)
  463. {
  464. throw JsonSerializationException.Create(reader, "Cannot preserve reference to readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  465. }
  466. if (contract.OnSerializingCallbacks.Count > 0)
  467. {
  468. throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on readonly dictionary, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  469. }
  470. if (contract.OnErrorCallbacks.Count > 0)
  471. {
  472. throw JsonSerializationException.Create(reader, "Cannot call OnError on readonly list, or dictionary created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  473. }
  474. if (!dictionaryContract.HasParameterizedCreatorInternal)
  475. {
  476. throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size dictionary: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  477. }
  478. }
  479. PopulateDictionary(dictionary, reader, dictionaryContract, member, id);
  480. if (createdFromNonDefaultCreator)
  481. {
  482. ObjectConstructor<object> creator = dictionaryContract.OverrideCreator ?? dictionaryContract.ParameterizedCreator;
  483. return creator(dictionary);
  484. }
  485. else if (dictionary is IWrappedDictionary)
  486. {
  487. return ((IWrappedDictionary)dictionary).UnderlyingDictionary;
  488. }
  489. targetDictionary = dictionary;
  490. }
  491. else
  492. {
  493. targetDictionary = PopulateDictionary(dictionaryContract.ShouldCreateWrapper || !(existingValue is IDictionary) ? dictionaryContract.CreateWrapper(existingValue) : (IDictionary)existingValue, reader, dictionaryContract, member, id);
  494. }
  495. return targetDictionary;
  496. }
  497. #if !NET20
  498. case JsonContractType.Dynamic:
  499. JsonDynamicContract dynamicContract = (JsonDynamicContract)contract;
  500. return CreateDynamic(reader, dynamicContract, member, id);
  501. #endif
  502. #if HAVE_BINARY_SERIALIZATION
  503. case JsonContractType.Serializable:
  504. JsonISerializableContract serializableContract = (JsonISerializableContract)contract;
  505. return CreateISerializable(reader, serializableContract, member, id);
  506. #endif
  507. }
  508. string message = @"Cannot deserialize the current JSON object (e.g. {{""name"":""value""}}) into type '{0}' because the type requires a {1} to deserialize correctly." + Environment.NewLine +
  509. @"To fix this error either change the JSON to a {1} or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object." + Environment.NewLine;
  510. message = message.FormatWith(CultureInfo.InvariantCulture, resolvedObjectType, GetExpectedDescription(contract));
  511. throw JsonSerializationException.Create(reader, message);
  512. }
  513. private bool ReadMetadataPropertiesToken(JTokenReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
  514. {
  515. id = null;
  516. newValue = null;
  517. if (reader.TokenType == JsonToken.StartObject)
  518. {
  519. JObject current = (JObject)reader.CurrentToken;
  520. JToken refToken = current[JsonTypeReflector.RefPropertyName];
  521. if (refToken != null)
  522. {
  523. if (refToken.Type != JTokenType.String && refToken.Type != JTokenType.Null)
  524. {
  525. throw JsonSerializationException.Create(refToken, refToken.Path, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);
  526. }
  527. JToken property = refToken.Parent;
  528. JToken additionalContent = null;
  529. if (property.Next != null)
  530. {
  531. additionalContent = property.Next;
  532. }
  533. else if (property.Previous != null)
  534. {
  535. additionalContent = property.Previous;
  536. }
  537. string reference = (string)refToken;
  538. if (reference != null)
  539. {
  540. if (additionalContent != null)
  541. {
  542. throw JsonSerializationException.Create(additionalContent, additionalContent.Path, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName), null);
  543. }
  544. newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);
  545. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  546. {
  547. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);
  548. }
  549. reader.Skip();
  550. return true;
  551. }
  552. }
  553. JToken typeToken = current[JsonTypeReflector.TypePropertyName];
  554. if (typeToken != null)
  555. {
  556. string qualifiedTypeName = (string)typeToken;
  557. JsonReader typeTokenReader = typeToken.CreateReader();
  558. typeTokenReader.ReadAndAssert();
  559. ResolveTypeName(typeTokenReader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);
  560. JToken valueToken = current[JsonTypeReflector.ValuePropertyName];
  561. if (valueToken != null)
  562. {
  563. while (true)
  564. {
  565. reader.ReadAndAssert();
  566. if (reader.TokenType == JsonToken.PropertyName)
  567. {
  568. if ((string)reader.Value == JsonTypeReflector.ValuePropertyName)
  569. {
  570. return false;
  571. }
  572. }
  573. reader.ReadAndAssert();
  574. reader.Skip();
  575. }
  576. }
  577. }
  578. JToken idToken = current[JsonTypeReflector.IdPropertyName];
  579. if (idToken != null)
  580. {
  581. id = (string)idToken;
  582. }
  583. JToken valuesToken = current[JsonTypeReflector.ArrayValuesPropertyName];
  584. if (valuesToken != null)
  585. {
  586. JsonReader listReader = valuesToken.CreateReader();
  587. listReader.ReadAndAssert();
  588. newValue = CreateList(listReader, objectType, contract, member, existingValue, id);
  589. reader.Skip();
  590. return true;
  591. }
  592. }
  593. reader.ReadAndAssert();
  594. return false;
  595. }
  596. private bool ReadMetadataProperties(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, object existingValue, out object newValue, out string id)
  597. {
  598. id = null;
  599. newValue = null;
  600. if (reader.TokenType == JsonToken.PropertyName)
  601. {
  602. string propertyName = reader.Value.ToString();
  603. if (propertyName.Length > 0 && propertyName[0] == '$')
  604. {
  605. // read metadata properties
  606. // $type, $id, $ref, etc
  607. bool metadataProperty;
  608. do
  609. {
  610. propertyName = reader.Value.ToString();
  611. if (string.Equals(propertyName, JsonTypeReflector.RefPropertyName, StringComparison.Ordinal))
  612. {
  613. reader.ReadAndAssert();
  614. if (reader.TokenType != JsonToken.String && reader.TokenType != JsonToken.Null)
  615. {
  616. throw JsonSerializationException.Create(reader, "JSON reference {0} property must have a string or null value.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
  617. }
  618. string reference = reader.Value?.ToString();
  619. reader.ReadAndAssert();
  620. if (reference != null)
  621. {
  622. if (reader.TokenType == JsonToken.PropertyName)
  623. {
  624. throw JsonSerializationException.Create(reader, "Additional content found in JSON reference object. A JSON reference object should only have a {0} property.".FormatWith(CultureInfo.InvariantCulture, JsonTypeReflector.RefPropertyName));
  625. }
  626. newValue = Serializer.GetReferenceResolver().ResolveReference(this, reference);
  627. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  628. {
  629. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved object reference '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, reference, newValue.GetType())), null);
  630. }
  631. return true;
  632. }
  633. else
  634. {
  635. metadataProperty = true;
  636. }
  637. }
  638. else if (string.Equals(propertyName, JsonTypeReflector.TypePropertyName, StringComparison.Ordinal))
  639. {
  640. reader.ReadAndAssert();
  641. string qualifiedTypeName = reader.Value.ToString();
  642. ResolveTypeName(reader, ref objectType, ref contract, member, containerContract, containerMember, qualifiedTypeName);
  643. reader.ReadAndAssert();
  644. metadataProperty = true;
  645. }
  646. else if (string.Equals(propertyName, JsonTypeReflector.IdPropertyName, StringComparison.Ordinal))
  647. {
  648. reader.ReadAndAssert();
  649. id = reader.Value?.ToString();
  650. reader.ReadAndAssert();
  651. metadataProperty = true;
  652. }
  653. else if (string.Equals(propertyName, JsonTypeReflector.ArrayValuesPropertyName, StringComparison.Ordinal))
  654. {
  655. reader.ReadAndAssert();
  656. object list = CreateList(reader, objectType, contract, member, existingValue, id);
  657. reader.ReadAndAssert();
  658. newValue = list;
  659. return true;
  660. }
  661. else
  662. {
  663. metadataProperty = false;
  664. }
  665. } while (metadataProperty && reader.TokenType == JsonToken.PropertyName);
  666. }
  667. }
  668. return false;
  669. }
  670. private void ResolveTypeName(JsonReader reader, ref Type objectType, ref JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, string qualifiedTypeName)
  671. {
  672. TypeNameHandling resolvedTypeNameHandling =
  673. member?.TypeNameHandling
  674. ?? containerContract?.ItemTypeNameHandling
  675. ?? containerMember?.ItemTypeNameHandling
  676. ?? Serializer._typeNameHandling;
  677. if (resolvedTypeNameHandling != TypeNameHandling.None)
  678. {
  679. TypeNameKey typeNameKey = ReflectionUtils.SplitFullyQualifiedTypeName(qualifiedTypeName);
  680. Type specifiedType;
  681. try
  682. {
  683. specifiedType = Serializer._serializationBinder.BindToType(typeNameKey.AssemblyName, typeNameKey.TypeName);
  684. }
  685. catch (Exception ex)
  686. {
  687. throw JsonSerializationException.Create(reader, "Error resolving type specified in JSON '{0}'.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName), ex);
  688. }
  689. if (specifiedType == null)
  690. {
  691. throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' was not resolved.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName));
  692. }
  693. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  694. {
  695. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Resolved type '{0}' to {1}.".FormatWith(CultureInfo.InvariantCulture, qualifiedTypeName, specifiedType)), null);
  696. }
  697. if (objectType != null
  698. #if !NET20
  699. && objectType != typeof(IDynamicMetaObjectProvider)
  700. #endif
  701. && !objectType.IsAssignableFrom(specifiedType))
  702. {
  703. throw JsonSerializationException.Create(reader, "Type specified in JSON '{0}' is not compatible with '{1}'.".FormatWith(CultureInfo.InvariantCulture, specifiedType.AssemblyQualifiedName, objectType.AssemblyQualifiedName));
  704. }
  705. objectType = specifiedType;
  706. contract = GetContractSafe(specifiedType);
  707. }
  708. }
  709. private JsonArrayContract EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)
  710. {
  711. if (contract == null)
  712. {
  713. throw JsonSerializationException.Create(reader, "Could not resolve type '{0}' to a JsonContract.".FormatWith(CultureInfo.InvariantCulture, objectType));
  714. }
  715. if (!(contract is JsonArrayContract arrayContract))
  716. {
  717. string message = @"Cannot deserialize the current JSON array (e.g. [1,2,3]) into type '{0}' because the type requires a {1} to deserialize correctly." + Environment.NewLine +
  718. @"To fix this error either change the JSON to a {1} or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array." + Environment.NewLine;
  719. message = message.FormatWith(CultureInfo.InvariantCulture, objectType, GetExpectedDescription(contract));
  720. throw JsonSerializationException.Create(reader, message);
  721. }
  722. return arrayContract;
  723. }
  724. private object CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, object existingValue, string id)
  725. {
  726. object value;
  727. if (HasNoDefinedType(contract))
  728. {
  729. return CreateJToken(reader, contract);
  730. }
  731. JsonArrayContract arrayContract = EnsureArrayContract(reader, objectType, contract);
  732. if (existingValue == null)
  733. {
  734. IList list = CreateNewList(reader, arrayContract, out bool createdFromNonDefaultCreator);
  735. if (createdFromNonDefaultCreator)
  736. {
  737. if (id != null)
  738. {
  739. throw JsonSerializationException.Create(reader, "Cannot preserve reference to array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  740. }
  741. if (contract.OnSerializingCallbacks.Count > 0)
  742. {
  743. throw JsonSerializationException.Create(reader, "Cannot call OnSerializing on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  744. }
  745. if (contract.OnErrorCallbacks.Count > 0)
  746. {
  747. throw JsonSerializationException.Create(reader, "Cannot call OnError on an array or readonly list, or list created from a non-default constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  748. }
  749. if (!arrayContract.HasParameterizedCreatorInternal && !arrayContract.IsArray)
  750. {
  751. throw JsonSerializationException.Create(reader, "Cannot deserialize readonly or fixed size list: {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  752. }
  753. }
  754. if (!arrayContract.IsMultidimensionalArray)
  755. {
  756. PopulateList(list, reader, arrayContract, member, id);
  757. }
  758. else
  759. {
  760. PopulateMultidimensionalArray(list, reader, arrayContract, member, id);
  761. }
  762. if (createdFromNonDefaultCreator)
  763. {
  764. if (arrayContract.IsMultidimensionalArray)
  765. {
  766. list = CollectionUtils.ToMultidimensionalArray(list, arrayContract.CollectionItemType, contract.CreatedType.GetArrayRank());
  767. }
  768. else if (arrayContract.IsArray)
  769. {
  770. Array a = Array.CreateInstance(arrayContract.CollectionItemType, list.Count);
  771. list.CopyTo(a, 0);
  772. list = a;
  773. }
  774. else
  775. {
  776. ObjectConstructor<object> creator = arrayContract.OverrideCreator ?? arrayContract.ParameterizedCreator;
  777. return creator(list);
  778. }
  779. }
  780. else if (list is IWrappedCollection)
  781. {
  782. return ((IWrappedCollection)list).UnderlyingCollection;
  783. }
  784. value = list;
  785. }
  786. else
  787. {
  788. if (!arrayContract.CanDeserialize)
  789. {
  790. throw JsonSerializationException.Create(reader, "Cannot populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));
  791. }
  792. value = PopulateList((arrayContract.ShouldCreateWrapper || !(existingValue is IList)) ? arrayContract.CreateWrapper(existingValue) : (IList)existingValue, reader, arrayContract, member, id);
  793. }
  794. return value;
  795. }
  796. private bool HasNoDefinedType(JsonContract contract)
  797. {
  798. return (contract == null || contract.UnderlyingType == typeof(object) || contract.ContractType == JsonContractType.Linq
  799. #if !NET20
  800. || contract.UnderlyingType == typeof(IDynamicMetaObjectProvider)
  801. #endif
  802. );
  803. }
  804. private object EnsureType(JsonReader reader, object value, CultureInfo culture, JsonContract contract, Type targetType)
  805. {
  806. if (targetType == null)
  807. {
  808. return value;
  809. }
  810. Type valueType = ReflectionUtils.GetObjectType(value);
  811. // type of value and type of target don't match
  812. // attempt to convert value's type to target's type
  813. if (valueType != targetType)
  814. {
  815. if (value == null && contract.IsNullable)
  816. {
  817. return null;
  818. }
  819. try
  820. {
  821. if (contract.IsConvertable)
  822. {
  823. JsonPrimitiveContract primitiveContract = (JsonPrimitiveContract)contract;
  824. if (contract.IsEnum)
  825. {
  826. if (value is string)
  827. {
  828. return EnumUtils.ParseEnum(contract.NonNullableUnderlyingType, value.ToString(), false);
  829. }
  830. if (ConvertUtils.IsInteger(primitiveContract.TypeCode))
  831. {
  832. return Enum.ToObject(contract.NonNullableUnderlyingType, value);
  833. }
  834. }
  835. #if HAVE_BIG_INTEGER
  836. if (value is BigInteger integer)
  837. {
  838. return ConvertUtils.FromBigInteger(integer, contract.NonNullableUnderlyingType);
  839. }
  840. #endif
  841. // this won't work when converting to a custom IConvertible
  842. return Convert.ChangeType(value, contract.NonNullableUnderlyingType, culture);
  843. }
  844. return ConvertUtils.ConvertOrCast(value, culture, contract.NonNullableUnderlyingType);
  845. }
  846. catch (Exception ex)
  847. {
  848. throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(value), targetType), ex);
  849. }
  850. }
  851. return value;
  852. }
  853. private bool SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target)
  854. {
  855. if (CalculatePropertyDetails(property, ref propertyConverter, containerContract, containerProperty, reader, target, out bool useExistingValue, out object currentValue, out JsonContract propertyContract, out bool gottenCurrentValue))
  856. {
  857. return false;
  858. }
  859. object value;
  860. if (propertyConverter != null && propertyConverter.CanRead)
  861. {
  862. if (!gottenCurrentValue && target != null && property.Readable)
  863. {
  864. currentValue = property.ValueProvider.GetValue(target);
  865. }
  866. value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, currentValue);
  867. }
  868. else
  869. {
  870. value = CreateValueInternal(reader, property.PropertyType, propertyContract, property, containerContract, containerProperty, (useExistingValue) ? currentValue : null);
  871. }
  872. // always set the value if useExistingValue is false,
  873. // otherwise also set it if CreateValue returns a new value compared to the currentValue
  874. // this could happen because of a JsonConverter against the type
  875. if ((!useExistingValue || value != currentValue)
  876. && ShouldSetPropertyValue(property, containerContract as JsonObjectContract, value))
  877. {
  878. property.ValueProvider.SetValue(target, value);
  879. if (property.SetIsSpecified != null)
  880. {
  881. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  882. {
  883. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "IsSpecified for property '{0}' on {1} set to true.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.DeclaringType)), null);
  884. }
  885. property.SetIsSpecified(target, true);
  886. }
  887. return true;
  888. }
  889. // the value wasn't set be JSON was populated onto the existing value
  890. return useExistingValue;
  891. }
  892. private bool CalculatePropertyDetails(JsonProperty property, ref JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, object target, out bool useExistingValue, out object currentValue, out JsonContract propertyContract, out bool gottenCurrentValue)
  893. {
  894. currentValue = null;
  895. useExistingValue = false;
  896. propertyContract = null;
  897. gottenCurrentValue = false;
  898. if (property.Ignored)
  899. {
  900. return true;
  901. }
  902. JsonToken tokenType = reader.TokenType;
  903. if (property.PropertyContract == null)
  904. {
  905. property.PropertyContract = GetContractSafe(property.PropertyType);
  906. }
  907. ObjectCreationHandling objectCreationHandling =
  908. property.ObjectCreationHandling.GetValueOrDefault(Serializer._objectCreationHandling);
  909. if ((objectCreationHandling != ObjectCreationHandling.Replace)
  910. && (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject || propertyConverter != null)
  911. && property.Readable)
  912. {
  913. currentValue = property.ValueProvider.GetValue(target);
  914. gottenCurrentValue = true;
  915. if (currentValue != null)
  916. {
  917. propertyContract = GetContractSafe(currentValue.GetType());
  918. useExistingValue = (!propertyContract.IsReadOnlyOrFixedSize && !propertyContract.UnderlyingType.IsValueType());
  919. }
  920. }
  921. if (!property.Writable && !useExistingValue)
  922. {
  923. return true;
  924. }
  925. // test tokenType here because null might not be convertible to some types, e.g. ignoring null when applied to DateTime
  926. if (tokenType == JsonToken.Null && ResolvedNullValueHandling(containerContract as JsonObjectContract, property) == NullValueHandling.Ignore)
  927. {
  928. return true;
  929. }
  930. // test tokenType here because default value might not be convertible to actual type, e.g. default of "" for DateTime
  931. if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore)
  932. && !HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate)
  933. && JsonTokenUtils.IsPrimitiveToken(tokenType)
  934. && MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue()))
  935. {
  936. return true;
  937. }
  938. if (currentValue == null)
  939. {
  940. propertyContract = property.PropertyContract;
  941. }
  942. else
  943. {
  944. propertyContract = GetContractSafe(currentValue.GetType());
  945. if (propertyContract != property.PropertyContract)
  946. {
  947. propertyConverter = GetConverter(propertyContract, property.Converter, containerContract, containerProperty);
  948. }
  949. }
  950. return false;
  951. }
  952. private void AddReference(JsonReader reader, string id, object value)
  953. {
  954. try
  955. {
  956. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  957. {
  958. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Read object reference Id '{0}' for {1}.".FormatWith(CultureInfo.InvariantCulture, id, value.GetType())), null);
  959. }
  960. Serializer.GetReferenceResolver().AddReference(this, id, value);
  961. }
  962. catch (Exception ex)
  963. {
  964. throw JsonSerializationException.Create(reader, "Error reading object reference '{0}'.".FormatWith(CultureInfo.InvariantCulture, id), ex);
  965. }
  966. }
  967. private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag)
  968. {
  969. return ((value & flag) == flag);
  970. }
  971. private bool ShouldSetPropertyValue(JsonProperty property, JsonObjectContract contract, object value)
  972. {
  973. if (value == null && ResolvedNullValueHandling(contract, property) == NullValueHandling.Ignore)
  974. {
  975. return false;
  976. }
  977. if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Ignore)
  978. && !HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate)
  979. && MiscellaneousUtils.ValueEquals(value, property.GetResolvedDefaultValue()))
  980. {
  981. return false;
  982. }
  983. if (!property.Writable)
  984. {
  985. return false;
  986. }
  987. return true;
  988. }
  989. private IList CreateNewList(JsonReader reader, JsonArrayContract contract, out bool createdFromNonDefaultCreator)
  990. {
  991. // some types like non-generic IEnumerable can be serialized but not deserialized
  992. if (!contract.CanDeserialize)
  993. {
  994. throw JsonSerializationException.Create(reader, "Cannot create and populate list type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.CreatedType));
  995. }
  996. if (contract.OverrideCreator != null)
  997. {
  998. if (contract.HasParameterizedCreator)
  999. {
  1000. createdFromNonDefaultCreator = true;
  1001. return contract.CreateTemporaryCollection();
  1002. }
  1003. else
  1004. {
  1005. object list = contract.OverrideCreator();
  1006. if (contract.ShouldCreateWrapper)
  1007. {
  1008. list = contract.CreateWrapper(list);
  1009. }
  1010. createdFromNonDefaultCreator = false;
  1011. return (IList)list;
  1012. }
  1013. }
  1014. else if (contract.IsReadOnlyOrFixedSize)
  1015. {
  1016. createdFromNonDefaultCreator = true;
  1017. IList list = contract.CreateTemporaryCollection();
  1018. if (contract.ShouldCreateWrapper)
  1019. {
  1020. list = contract.CreateWrapper(list);
  1021. }
  1022. return list;
  1023. }
  1024. else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
  1025. {
  1026. object list = contract.DefaultCreator();
  1027. if (contract.ShouldCreateWrapper)
  1028. {
  1029. list = contract.CreateWrapper(list);
  1030. }
  1031. createdFromNonDefaultCreator = false;
  1032. return (IList)list;
  1033. }
  1034. else if (contract.HasParameterizedCreatorInternal)
  1035. {
  1036. createdFromNonDefaultCreator = true;
  1037. return contract.CreateTemporaryCollection();
  1038. }
  1039. else
  1040. {
  1041. if (!contract.IsInstantiable)
  1042. {
  1043. throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1044. }
  1045. throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1046. }
  1047. }
  1048. private IDictionary CreateNewDictionary(JsonReader reader, JsonDictionaryContract contract, out bool createdFromNonDefaultCreator)
  1049. {
  1050. if (contract.OverrideCreator != null)
  1051. {
  1052. if (contract.HasParameterizedCreator)
  1053. {
  1054. createdFromNonDefaultCreator = true;
  1055. return contract.CreateTemporaryDictionary();
  1056. }
  1057. else
  1058. {
  1059. createdFromNonDefaultCreator = false;
  1060. return (IDictionary)contract.OverrideCreator();
  1061. }
  1062. }
  1063. else if (contract.IsReadOnlyOrFixedSize)
  1064. {
  1065. createdFromNonDefaultCreator = true;
  1066. return contract.CreateTemporaryDictionary();
  1067. }
  1068. else if (contract.DefaultCreator != null && (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
  1069. {
  1070. object dictionary = contract.DefaultCreator();
  1071. if (contract.ShouldCreateWrapper)
  1072. {
  1073. dictionary = contract.CreateWrapper(dictionary);
  1074. }
  1075. createdFromNonDefaultCreator = false;
  1076. return (IDictionary)dictionary;
  1077. }
  1078. else if (contract.HasParameterizedCreatorInternal)
  1079. {
  1080. createdFromNonDefaultCreator = true;
  1081. return contract.CreateTemporaryDictionary();
  1082. }
  1083. else
  1084. {
  1085. if (!contract.IsInstantiable)
  1086. {
  1087. throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1088. }
  1089. throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1090. }
  1091. }
  1092. private void OnDeserializing(JsonReader reader, JsonContract contract, object value)
  1093. {
  1094. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1095. {
  1096. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
  1097. }
  1098. contract.InvokeOnDeserializing(value, Serializer._context);
  1099. }
  1100. private void OnDeserialized(JsonReader reader, JsonContract contract, object value)
  1101. {
  1102. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1103. {
  1104. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Finished deserializing {0}".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
  1105. }
  1106. contract.InvokeOnDeserialized(value, Serializer._context);
  1107. }
  1108. private object PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, string id)
  1109. {
  1110. object underlyingDictionary = dictionary is IWrappedDictionary wrappedDictionary ? wrappedDictionary.UnderlyingDictionary : dictionary;
  1111. if (id != null)
  1112. {
  1113. AddReference(reader, id, underlyingDictionary);
  1114. }
  1115. OnDeserializing(reader, contract, underlyingDictionary);
  1116. int initialDepth = reader.Depth;
  1117. if (contract.KeyContract == null)
  1118. {
  1119. contract.KeyContract = GetContractSafe(contract.DictionaryKeyType);
  1120. }
  1121. if (contract.ItemContract == null)
  1122. {
  1123. contract.ItemContract = GetContractSafe(contract.DictionaryValueType);
  1124. }
  1125. JsonConverter dictionaryValueConverter = contract.ItemConverter ?? GetConverter(contract.ItemContract, null, contract, containerProperty);
  1126. PrimitiveTypeCode keyTypeCode = (contract.KeyContract is JsonPrimitiveContract keyContract) ? keyContract.TypeCode : PrimitiveTypeCode.Empty;
  1127. bool finished = false;
  1128. do
  1129. {
  1130. switch (reader.TokenType)
  1131. {
  1132. case JsonToken.PropertyName:
  1133. object keyValue = reader.Value;
  1134. if (CheckPropertyName(reader, keyValue.ToString()))
  1135. {
  1136. continue;
  1137. }
  1138. try
  1139. {
  1140. try
  1141. {
  1142. // this is for correctly reading ISO and MS formatted dictionary keys
  1143. switch (keyTypeCode)
  1144. {
  1145. case PrimitiveTypeCode.DateTime:
  1146. case PrimitiveTypeCode.DateTimeNullable:
  1147. {
  1148. keyValue = DateTimeUtils.TryParseDateTime(keyValue.ToString(), reader.DateTimeZoneHandling, reader.DateFormatString, reader.Culture, out DateTime dt)
  1149. ? dt
  1150. : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);
  1151. break;
  1152. }
  1153. #if !NET20
  1154. case PrimitiveTypeCode.DateTimeOffset:
  1155. case PrimitiveTypeCode.DateTimeOffsetNullable:
  1156. {
  1157. keyValue = DateTimeUtils.TryParseDateTimeOffset(keyValue.ToString(), reader.DateFormatString, reader.Culture, out DateTimeOffset dt)
  1158. ? dt
  1159. : EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);
  1160. break;
  1161. }
  1162. #endif
  1163. default:
  1164. keyValue = EnsureType(reader, keyValue, CultureInfo.InvariantCulture, contract.KeyContract, contract.DictionaryKeyType);
  1165. break;
  1166. }
  1167. }
  1168. catch (Exception ex)
  1169. {
  1170. throw JsonSerializationException.Create(reader, "Could not convert string '{0}' to dictionary key type '{1}'. Create a TypeConverter to convert from the string to the key type object.".FormatWith(CultureInfo.InvariantCulture, reader.Value, contract.DictionaryKeyType), ex);
  1171. }
  1172. if (!reader.ReadForType(contract.ItemContract, dictionaryValueConverter != null))
  1173. {
  1174. throw JsonSerializationException.Create(reader, "Unexpected end when deserializing object.");
  1175. }
  1176. object itemValue;
  1177. if (dictionaryValueConverter != null && dictionaryValueConverter.CanRead)
  1178. {
  1179. itemValue = DeserializeConvertable(dictionaryValueConverter, reader, contract.DictionaryValueType, null);
  1180. }
  1181. else
  1182. {
  1183. itemValue = CreateValueInternal(reader, contract.DictionaryValueType, contract.ItemContract, null, contract, containerProperty, null);
  1184. }
  1185. dictionary[keyValue] = itemValue;
  1186. }
  1187. catch (Exception ex)
  1188. {
  1189. if (IsErrorHandled(underlyingDictionary, contract, keyValue, reader as IJsonLineInfo, reader.Path, ex))
  1190. {
  1191. HandleError(reader, true, initialDepth);
  1192. }
  1193. else
  1194. {
  1195. throw;
  1196. }
  1197. }
  1198. break;
  1199. case JsonToken.Comment:
  1200. break;
  1201. case JsonToken.EndObject:
  1202. finished = true;
  1203. break;
  1204. default:
  1205. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
  1206. }
  1207. } while (!finished && reader.Read());
  1208. if (!finished)
  1209. {
  1210. ThrowUnexpectedEndException(reader, contract, underlyingDictionary, "Unexpected end when deserializing object.");
  1211. }
  1212. OnDeserialized(reader, contract, underlyingDictionary);
  1213. return underlyingDictionary;
  1214. }
  1215. private object PopulateMultidimensionalArray(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
  1216. {
  1217. int rank = contract.UnderlyingType.GetArrayRank();
  1218. if (id != null)
  1219. {
  1220. AddReference(reader, id, list);
  1221. }
  1222. OnDeserializing(reader, contract, list);
  1223. JsonContract collectionItemContract = GetContractSafe(contract.CollectionItemType);
  1224. JsonConverter collectionItemConverter = GetConverter(collectionItemContract, null, contract, containerProperty);
  1225. int? previousErrorIndex = null;
  1226. Stack<IList> listStack = new Stack<IList>();
  1227. listStack.Push(list);
  1228. IList currentList = list;
  1229. bool finished = false;
  1230. do
  1231. {
  1232. int initialDepth = reader.Depth;
  1233. if (listStack.Count == rank)
  1234. {
  1235. try
  1236. {
  1237. if (reader.ReadForType(collectionItemContract, collectionItemConverter != null))
  1238. {
  1239. switch (reader.TokenType)
  1240. {
  1241. case JsonToken.EndArray:
  1242. listStack.Pop();
  1243. currentList = listStack.Peek();
  1244. previousErrorIndex = null;
  1245. break;
  1246. case JsonToken.Comment:
  1247. break;
  1248. default:
  1249. object value;
  1250. if (collectionItemConverter != null && collectionItemConverter.CanRead)
  1251. {
  1252. value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
  1253. }
  1254. else
  1255. {
  1256. value = CreateValueInternal(reader, contract.CollectionItemType, collectionItemContract, null, contract, containerProperty, null);
  1257. }
  1258. currentList.Add(value);
  1259. break;
  1260. }
  1261. }
  1262. else
  1263. {
  1264. break;
  1265. }
  1266. }
  1267. catch (Exception ex)
  1268. {
  1269. JsonPosition errorPosition = reader.GetPosition(initialDepth);
  1270. if (IsErrorHandled(list, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
  1271. {
  1272. HandleError(reader, true, initialDepth + 1);
  1273. if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
  1274. {
  1275. // reader index has not moved since previous error handling
  1276. // break out of reading array to prevent infinite loop
  1277. throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
  1278. }
  1279. else
  1280. {
  1281. previousErrorIndex = errorPosition.Position;
  1282. }
  1283. }
  1284. else
  1285. {
  1286. throw;
  1287. }
  1288. }
  1289. }
  1290. else
  1291. {
  1292. if (reader.Read())
  1293. {
  1294. switch (reader.TokenType)
  1295. {
  1296. case JsonToken.StartArray:
  1297. IList newList = new List<object>();
  1298. currentList.Add(newList);
  1299. listStack.Push(newList);
  1300. currentList = newList;
  1301. break;
  1302. case JsonToken.EndArray:
  1303. listStack.Pop();
  1304. if (listStack.Count > 0)
  1305. {
  1306. currentList = listStack.Peek();
  1307. }
  1308. else
  1309. {
  1310. finished = true;
  1311. }
  1312. break;
  1313. case JsonToken.Comment:
  1314. break;
  1315. default:
  1316. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing multidimensional array: " + reader.TokenType);
  1317. }
  1318. }
  1319. else
  1320. {
  1321. break;
  1322. }
  1323. }
  1324. } while (!finished);
  1325. if (!finished)
  1326. {
  1327. ThrowUnexpectedEndException(reader, contract, list, "Unexpected end when deserializing array.");
  1328. }
  1329. OnDeserialized(reader, contract, list);
  1330. return list;
  1331. }
  1332. private void ThrowUnexpectedEndException(JsonReader reader, JsonContract contract, object currentObject, string message)
  1333. {
  1334. try
  1335. {
  1336. throw JsonSerializationException.Create(reader, message);
  1337. }
  1338. catch (Exception ex)
  1339. {
  1340. if (IsErrorHandled(currentObject, contract, null, reader as IJsonLineInfo, reader.Path, ex))
  1341. {
  1342. HandleError(reader, false, 0);
  1343. }
  1344. else
  1345. {
  1346. throw;
  1347. }
  1348. }
  1349. }
  1350. private object PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, string id)
  1351. {
  1352. object underlyingList = list is IWrappedCollection wrappedCollection ? wrappedCollection.UnderlyingCollection : list;
  1353. if (id != null)
  1354. {
  1355. AddReference(reader, id, underlyingList);
  1356. }
  1357. // can't populate an existing array
  1358. if (list.IsFixedSize)
  1359. {
  1360. reader.Skip();
  1361. return underlyingList;
  1362. }
  1363. OnDeserializing(reader, contract, underlyingList);
  1364. int initialDepth = reader.Depth;
  1365. if (contract.ItemContract == null)
  1366. {
  1367. contract.ItemContract = GetContractSafe(contract.CollectionItemType);
  1368. }
  1369. JsonConverter collectionItemConverter = GetConverter(contract.ItemContract, null, contract, containerProperty);
  1370. int? previousErrorIndex = null;
  1371. bool finished = false;
  1372. do
  1373. {
  1374. try
  1375. {
  1376. if (reader.ReadForType(contract.ItemContract, collectionItemConverter != null))
  1377. {
  1378. switch (reader.TokenType)
  1379. {
  1380. case JsonToken.EndArray:
  1381. finished = true;
  1382. break;
  1383. case JsonToken.Comment:
  1384. break;
  1385. default:
  1386. object value;
  1387. if (collectionItemConverter != null && collectionItemConverter.CanRead)
  1388. {
  1389. value = DeserializeConvertable(collectionItemConverter, reader, contract.CollectionItemType, null);
  1390. }
  1391. else
  1392. {
  1393. value = CreateValueInternal(reader, contract.CollectionItemType, contract.ItemContract, null, contract, containerProperty, null);
  1394. }
  1395. list.Add(value);
  1396. break;
  1397. }
  1398. }
  1399. else
  1400. {
  1401. break;
  1402. }
  1403. }
  1404. catch (Exception ex)
  1405. {
  1406. JsonPosition errorPosition = reader.GetPosition(initialDepth);
  1407. if (IsErrorHandled(underlyingList, contract, errorPosition.Position, reader as IJsonLineInfo, reader.Path, ex))
  1408. {
  1409. HandleError(reader, true, initialDepth + 1);
  1410. if (previousErrorIndex != null && previousErrorIndex == errorPosition.Position)
  1411. {
  1412. // reader index has not moved since previous error handling
  1413. // break out of reading array to prevent infinite loop
  1414. throw JsonSerializationException.Create(reader, "Infinite loop detected from error handling.", ex);
  1415. }
  1416. else
  1417. {
  1418. previousErrorIndex = errorPosition.Position;
  1419. }
  1420. }
  1421. else
  1422. {
  1423. throw;
  1424. }
  1425. }
  1426. } while (!finished);
  1427. if (!finished)
  1428. {
  1429. ThrowUnexpectedEndException(reader, contract, underlyingList, "Unexpected end when deserializing array.");
  1430. }
  1431. OnDeserialized(reader, contract, underlyingList);
  1432. return underlyingList;
  1433. }
  1434. #if HAVE_BINARY_SERIALIZATION
  1435. private object CreateISerializable(JsonReader reader, JsonISerializableContract contract, JsonProperty member, string id)
  1436. {
  1437. Type objectType = contract.UnderlyingType;
  1438. if (!JsonTypeReflector.FullyTrusted)
  1439. {
  1440. string message = @"Type '{0}' implements ISerializable but cannot be deserialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data." + Environment.NewLine +
  1441. @"To fix this error either change the environment to be fully trusted, change the application to not deserialize the type, add JsonObjectAttribute to the type or change the JsonSerializer setting ContractResolver to use a new DefaultContractResolver with IgnoreSerializableInterface set to true." + Environment.NewLine;
  1442. message = message.FormatWith(CultureInfo.InvariantCulture, objectType);
  1443. throw JsonSerializationException.Create(reader, message);
  1444. }
  1445. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1446. {
  1447. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using ISerializable constructor.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType)), null);
  1448. }
  1449. SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new JsonFormatterConverter(this, contract, member));
  1450. bool finished = false;
  1451. do
  1452. {
  1453. switch (reader.TokenType)
  1454. {
  1455. case JsonToken.PropertyName:
  1456. string memberName = reader.Value.ToString();
  1457. if (!reader.Read())
  1458. {
  1459. throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
  1460. }
  1461. serializationInfo.AddValue(memberName, JToken.ReadFrom(reader));
  1462. break;
  1463. case JsonToken.Comment:
  1464. break;
  1465. case JsonToken.EndObject:
  1466. finished = true;
  1467. break;
  1468. default:
  1469. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
  1470. }
  1471. } while (!finished && reader.Read());
  1472. if (!finished)
  1473. {
  1474. ThrowUnexpectedEndException(reader, contract, serializationInfo, "Unexpected end when deserializing object.");
  1475. }
  1476. if (contract.ISerializableCreator == null)
  1477. {
  1478. throw JsonSerializationException.Create(reader, "ISerializable type '{0}' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.".FormatWith(CultureInfo.InvariantCulture, objectType));
  1479. }
  1480. object createdObject = contract.ISerializableCreator(serializationInfo, Serializer._context);
  1481. if (id != null)
  1482. {
  1483. AddReference(reader, id, createdObject);
  1484. }
  1485. // these are together because OnDeserializing takes an object but for an ISerializable the object is fully created in the constructor
  1486. OnDeserializing(reader, contract, createdObject);
  1487. OnDeserialized(reader, contract, createdObject);
  1488. return createdObject;
  1489. }
  1490. internal object CreateISerializableItem(JToken token, Type type, JsonISerializableContract contract, JsonProperty member)
  1491. {
  1492. JsonContract itemContract = GetContractSafe(type);
  1493. JsonConverter itemConverter = GetConverter(itemContract, null, contract, member);
  1494. JsonReader tokenReader = token.CreateReader();
  1495. tokenReader.ReadAndAssert(); // Move to first token
  1496. object result;
  1497. if (itemConverter != null && itemConverter.CanRead)
  1498. {
  1499. result = DeserializeConvertable(itemConverter, tokenReader, type, null);
  1500. }
  1501. else
  1502. {
  1503. result = CreateValueInternal(tokenReader, type, itemContract, null, contract, member, null);
  1504. }
  1505. return result;
  1506. }
  1507. #endif
  1508. #if !NET20
  1509. private object CreateDynamic(JsonReader reader, JsonDynamicContract contract, JsonProperty member, string id)
  1510. {
  1511. IDynamicMetaObjectProvider newObject;
  1512. if (!contract.IsInstantiable)
  1513. {
  1514. throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1515. }
  1516. if (contract.DefaultCreator != null &&
  1517. (!contract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor))
  1518. {
  1519. newObject = (IDynamicMetaObjectProvider)contract.DefaultCreator();
  1520. }
  1521. else
  1522. {
  1523. throw JsonSerializationException.Create(reader, "Unable to find a default constructor to use for type {0}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType));
  1524. }
  1525. if (id != null)
  1526. {
  1527. AddReference(reader, id, newObject);
  1528. }
  1529. OnDeserializing(reader, contract, newObject);
  1530. int initialDepth = reader.Depth;
  1531. bool finished = false;
  1532. do
  1533. {
  1534. switch (reader.TokenType)
  1535. {
  1536. case JsonToken.PropertyName:
  1537. string memberName = reader.Value.ToString();
  1538. try
  1539. {
  1540. if (!reader.Read())
  1541. {
  1542. throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
  1543. }
  1544. // first attempt to find a settable property, otherwise fall back to a dynamic set without type
  1545. JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
  1546. if (property != null && property.Writable && !property.Ignored)
  1547. {
  1548. if (property.PropertyContract == null)
  1549. {
  1550. property.PropertyContract = GetContractSafe(property.PropertyType);
  1551. }
  1552. JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, null, null);
  1553. if (!SetPropertyValue(property, propertyConverter, null, member, reader, newObject))
  1554. {
  1555. reader.Skip();
  1556. }
  1557. }
  1558. else
  1559. {
  1560. Type t = (JsonTokenUtils.IsPrimitiveToken(reader.TokenType)) ? reader.ValueType : typeof(IDynamicMetaObjectProvider);
  1561. JsonContract dynamicMemberContract = GetContractSafe(t);
  1562. JsonConverter dynamicMemberConverter = GetConverter(dynamicMemberContract, null, null, member);
  1563. object value;
  1564. if (dynamicMemberConverter != null && dynamicMemberConverter.CanRead)
  1565. {
  1566. value = DeserializeConvertable(dynamicMemberConverter, reader, t, null);
  1567. }
  1568. else
  1569. {
  1570. value = CreateValueInternal(reader, t, dynamicMemberContract, null, null, member, null);
  1571. }
  1572. contract.TrySetMember(newObject, memberName, value);
  1573. }
  1574. }
  1575. catch (Exception ex)
  1576. {
  1577. if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
  1578. {
  1579. HandleError(reader, true, initialDepth);
  1580. }
  1581. else
  1582. {
  1583. throw;
  1584. }
  1585. }
  1586. break;
  1587. case JsonToken.EndObject:
  1588. finished = true;
  1589. break;
  1590. default:
  1591. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
  1592. }
  1593. } while (!finished && reader.Read());
  1594. if (!finished)
  1595. {
  1596. ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
  1597. }
  1598. OnDeserialized(reader, contract, newObject);
  1599. return newObject;
  1600. }
  1601. #endif
  1602. internal class CreatorPropertyContext
  1603. {
  1604. public string Name;
  1605. public JsonProperty Property;
  1606. public JsonProperty ConstructorProperty;
  1607. public PropertyPresence? Presence;
  1608. public object Value;
  1609. public bool Used;
  1610. }
  1611. private object CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor<object> creator, string id)
  1612. {
  1613. ValidationUtils.ArgumentNotNull(creator, nameof(creator));
  1614. // only need to keep a track of properties' presence if they are required or a value should be defaulted if missing
  1615. bool trackPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate));
  1616. Type objectType = contract.UnderlyingType;
  1617. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1618. {
  1619. string parameters = string.Join(", ", contract.CreatorParameters.Select(p => p.PropertyName)
  1620. #if NET20
  1621. .ToArray()
  1622. #endif
  1623. );
  1624. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Deserializing {0} using creator with parameters: {1}.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType, parameters)), null);
  1625. }
  1626. List<CreatorPropertyContext> propertyContexts = ResolvePropertyAndCreatorValues(contract, containerProperty, reader, objectType);
  1627. if (trackPresence)
  1628. {
  1629. foreach (JsonProperty property in contract.Properties)
  1630. {
  1631. if (propertyContexts.All(p => p.Property != property))
  1632. {
  1633. propertyContexts.Add(new CreatorPropertyContext
  1634. {
  1635. Property = property,
  1636. Name = property.PropertyName,
  1637. Presence = PropertyPresence.None
  1638. });
  1639. }
  1640. }
  1641. }
  1642. object[] creatorParameterValues = new object[contract.CreatorParameters.Count];
  1643. foreach (CreatorPropertyContext context in propertyContexts)
  1644. {
  1645. // set presence of read values
  1646. if (trackPresence)
  1647. {
  1648. if (context.Property != null && context.Presence == null)
  1649. {
  1650. object v = context.Value;
  1651. PropertyPresence propertyPresence;
  1652. if (v == null)
  1653. {
  1654. propertyPresence = PropertyPresence.Null;
  1655. }
  1656. else if (v is string)
  1657. {
  1658. propertyPresence = CoerceEmptyStringToNull(context.Property.PropertyType, context.Property.PropertyContract, (string)v)
  1659. ? PropertyPresence.Null
  1660. : PropertyPresence.Value;
  1661. }
  1662. else
  1663. {
  1664. propertyPresence = PropertyPresence.Value;
  1665. }
  1666. context.Presence = propertyPresence;
  1667. }
  1668. }
  1669. JsonProperty constructorProperty = context.ConstructorProperty;
  1670. if (constructorProperty == null && context.Property != null)
  1671. {
  1672. constructorProperty = contract.CreatorParameters.ForgivingCaseSensitiveFind(p => p.PropertyName, context.Property.UnderlyingName);
  1673. }
  1674. if (constructorProperty != null && !constructorProperty.Ignored)
  1675. {
  1676. // handle giving default values to creator parameters
  1677. // this needs to happen before the call to creator
  1678. if (trackPresence)
  1679. {
  1680. if (context.Presence == PropertyPresence.None || context.Presence == PropertyPresence.Null)
  1681. {
  1682. if (constructorProperty.PropertyContract == null)
  1683. {
  1684. constructorProperty.PropertyContract = GetContractSafe(constructorProperty.PropertyType);
  1685. }
  1686. if (HasFlag(constructorProperty.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate))
  1687. {
  1688. context.Value = EnsureType(
  1689. reader,
  1690. constructorProperty.GetResolvedDefaultValue(),
  1691. CultureInfo.InvariantCulture,
  1692. constructorProperty.PropertyContract,
  1693. constructorProperty.PropertyType);
  1694. }
  1695. }
  1696. }
  1697. int i = contract.CreatorParameters.IndexOf(constructorProperty);
  1698. creatorParameterValues[i] = context.Value;
  1699. context.Used = true;
  1700. }
  1701. }
  1702. object createdObject = creator(creatorParameterValues);
  1703. if (id != null)
  1704. {
  1705. AddReference(reader, id, createdObject);
  1706. }
  1707. OnDeserializing(reader, contract, createdObject);
  1708. // go through unused values and set the newly created object's properties
  1709. foreach (CreatorPropertyContext context in propertyContexts)
  1710. {
  1711. if (context.Used ||
  1712. context.Property == null ||
  1713. context.Property.Ignored ||
  1714. context.Presence == PropertyPresence.None)
  1715. {
  1716. continue;
  1717. }
  1718. JsonProperty property = context.Property;
  1719. object value = context.Value;
  1720. if (ShouldSetPropertyValue(property, contract, value))
  1721. {
  1722. property.ValueProvider.SetValue(createdObject, value);
  1723. context.Used = true;
  1724. }
  1725. else if (!property.Writable && value != null)
  1726. {
  1727. // handle readonly collection/dictionary properties
  1728. JsonContract propertyContract = Serializer._contractResolver.ResolveContract(property.PropertyType);
  1729. if (propertyContract.ContractType == JsonContractType.Array)
  1730. {
  1731. JsonArrayContract propertyArrayContract = (JsonArrayContract)propertyContract;
  1732. if (propertyArrayContract.CanDeserialize && !propertyArrayContract.IsReadOnlyOrFixedSize)
  1733. {
  1734. object createdObjectCollection = property.ValueProvider.GetValue(createdObject);
  1735. if (createdObjectCollection != null)
  1736. {
  1737. IList createdObjectCollectionWrapper = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(createdObjectCollection) : (IList)createdObjectCollection;
  1738. IList newValues = (propertyArrayContract.ShouldCreateWrapper) ? propertyArrayContract.CreateWrapper(value) : (IList)value;
  1739. foreach (object newValue in newValues)
  1740. {
  1741. createdObjectCollectionWrapper.Add(newValue);
  1742. }
  1743. }
  1744. }
  1745. }
  1746. else if (propertyContract.ContractType == JsonContractType.Dictionary)
  1747. {
  1748. JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)propertyContract;
  1749. if (!dictionaryContract.IsReadOnlyOrFixedSize)
  1750. {
  1751. object createdObjectDictionary = property.ValueProvider.GetValue(createdObject);
  1752. if (createdObjectDictionary != null)
  1753. {
  1754. IDictionary targetDictionary = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(createdObjectDictionary) : (IDictionary)createdObjectDictionary;
  1755. IDictionary newValues = (dictionaryContract.ShouldCreateWrapper) ? dictionaryContract.CreateWrapper(value) : (IDictionary)value;
  1756. // Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations.
  1757. IDictionaryEnumerator e = newValues.GetEnumerator();
  1758. try
  1759. {
  1760. while (e.MoveNext())
  1761. {
  1762. DictionaryEntry entry = e.Entry;
  1763. targetDictionary[entry.Key] = entry.Value;
  1764. }
  1765. }
  1766. finally
  1767. {
  1768. (e as IDisposable)?.Dispose();
  1769. }
  1770. }
  1771. }
  1772. }
  1773. context.Used = true;
  1774. }
  1775. }
  1776. if (contract.ExtensionDataSetter != null)
  1777. {
  1778. foreach (CreatorPropertyContext propertyValue in propertyContexts)
  1779. {
  1780. if (!propertyValue.Used)
  1781. {
  1782. contract.ExtensionDataSetter(createdObject, propertyValue.Name, propertyValue.Value);
  1783. }
  1784. }
  1785. }
  1786. if (trackPresence)
  1787. {
  1788. foreach (CreatorPropertyContext context in propertyContexts)
  1789. {
  1790. if (context.Property == null)
  1791. {
  1792. continue;
  1793. }
  1794. EndProcessProperty(
  1795. createdObject,
  1796. reader,
  1797. contract,
  1798. reader.Depth,
  1799. context.Property,
  1800. context.Presence.GetValueOrDefault(),
  1801. !context.Used);
  1802. }
  1803. }
  1804. OnDeserialized(reader, contract, createdObject);
  1805. return createdObject;
  1806. }
  1807. private object DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, object existingValue)
  1808. {
  1809. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1810. {
  1811. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Started deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null);
  1812. }
  1813. object value = converter.ReadJson(reader, objectType, existingValue, GetInternalSerializer());
  1814. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Info)
  1815. {
  1816. TraceWriter.Trace(TraceLevel.Info, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Finished deserializing {0} with converter {1}.".FormatWith(CultureInfo.InvariantCulture, objectType, converter.GetType())), null);
  1817. }
  1818. return value;
  1819. }
  1820. private List<CreatorPropertyContext> ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
  1821. {
  1822. List<CreatorPropertyContext> propertyValues = new List<CreatorPropertyContext>();
  1823. bool exit = false;
  1824. do
  1825. {
  1826. switch (reader.TokenType)
  1827. {
  1828. case JsonToken.PropertyName:
  1829. string memberName = reader.Value.ToString();
  1830. CreatorPropertyContext creatorPropertyContext = new CreatorPropertyContext
  1831. {
  1832. Name = reader.Value.ToString(),
  1833. ConstructorProperty = contract.CreatorParameters.GetClosestMatchProperty(memberName),
  1834. Property = contract.Properties.GetClosestMatchProperty(memberName)
  1835. };
  1836. propertyValues.Add(creatorPropertyContext);
  1837. JsonProperty property = creatorPropertyContext.ConstructorProperty ?? creatorPropertyContext.Property;
  1838. if (property != null && !property.Ignored)
  1839. {
  1840. if (property.PropertyContract == null)
  1841. {
  1842. property.PropertyContract = GetContractSafe(property.PropertyType);
  1843. }
  1844. JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, containerProperty);
  1845. if (!reader.ReadForType(property.PropertyContract, propertyConverter != null))
  1846. {
  1847. throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
  1848. }
  1849. if (propertyConverter != null && propertyConverter.CanRead)
  1850. {
  1851. creatorPropertyContext.Value = DeserializeConvertable(propertyConverter, reader, property.PropertyType, null);
  1852. }
  1853. else
  1854. {
  1855. creatorPropertyContext.Value = CreateValueInternal(reader, property.PropertyType, property.PropertyContract, property, contract, containerProperty, null);
  1856. }
  1857. continue;
  1858. }
  1859. else
  1860. {
  1861. if (!reader.Read())
  1862. {
  1863. throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
  1864. }
  1865. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  1866. {
  1867. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}.".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null);
  1868. }
  1869. if (Serializer._missingMemberHandling == MissingMemberHandling.Error)
  1870. {
  1871. throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, objectType.Name));
  1872. }
  1873. }
  1874. if (contract.ExtensionDataSetter != null)
  1875. {
  1876. creatorPropertyContext.Value = ReadExtensionDataValue(contract, containerProperty, reader);
  1877. }
  1878. else
  1879. {
  1880. reader.Skip();
  1881. }
  1882. break;
  1883. case JsonToken.Comment:
  1884. break;
  1885. case JsonToken.EndObject:
  1886. exit = true;
  1887. break;
  1888. default:
  1889. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
  1890. }
  1891. } while (!exit && reader.Read());
  1892. if (!exit)
  1893. {
  1894. ThrowUnexpectedEndException(reader, contract, null, "Unexpected end when deserializing object.");
  1895. }
  1896. return propertyValues;
  1897. }
  1898. public object CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, string id, out bool createdFromNonDefaultCreator)
  1899. {
  1900. object newObject = null;
  1901. if (objectContract.OverrideCreator != null)
  1902. {
  1903. if (objectContract.CreatorParameters.Count > 0)
  1904. {
  1905. createdFromNonDefaultCreator = true;
  1906. return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.OverrideCreator, id);
  1907. }
  1908. newObject = objectContract.OverrideCreator(CollectionUtils.ArrayEmpty<object>());
  1909. }
  1910. else if (objectContract.DefaultCreator != null &&
  1911. (!objectContract.DefaultCreatorNonPublic || Serializer._constructorHandling == ConstructorHandling.AllowNonPublicDefaultConstructor || objectContract.ParameterizedCreator == null))
  1912. {
  1913. // use the default constructor if it is...
  1914. // public
  1915. // non-public and the user has change constructor handling settings
  1916. // non-public and there is no other creator
  1917. newObject = objectContract.DefaultCreator();
  1918. }
  1919. else if (objectContract.ParameterizedCreator != null)
  1920. {
  1921. createdFromNonDefaultCreator = true;
  1922. return CreateObjectUsingCreatorWithParameters(reader, objectContract, containerMember, objectContract.ParameterizedCreator, id);
  1923. }
  1924. if (newObject == null)
  1925. {
  1926. if (!objectContract.IsInstantiable)
  1927. {
  1928. throw JsonSerializationException.Create(reader, "Could not create an instance of type {0}. Type is an interface or abstract class and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
  1929. }
  1930. throw JsonSerializationException.Create(reader, "Unable to find a constructor to use for type {0}. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.".FormatWith(CultureInfo.InvariantCulture, objectContract.UnderlyingType));
  1931. }
  1932. createdFromNonDefaultCreator = false;
  1933. return newObject;
  1934. }
  1935. private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id)
  1936. {
  1937. OnDeserializing(reader, contract, newObject);
  1938. // only need to keep a track of properties' presence if they are required or a value should be defaulted if missing
  1939. Dictionary<JsonProperty, PropertyPresence> propertiesPresence = (contract.HasRequiredOrDefaultValueProperties || HasFlag(Serializer._defaultValueHandling, DefaultValueHandling.Populate))
  1940. ? contract.Properties.ToDictionary(m => m, m => PropertyPresence.None)
  1941. : null;
  1942. if (id != null)
  1943. {
  1944. AddReference(reader, id, newObject);
  1945. }
  1946. int initialDepth = reader.Depth;
  1947. bool finished = false;
  1948. do
  1949. {
  1950. switch (reader.TokenType)
  1951. {
  1952. case JsonToken.PropertyName:
  1953. {
  1954. string memberName = reader.Value.ToString();
  1955. if (CheckPropertyName(reader, memberName))
  1956. {
  1957. continue;
  1958. }
  1959. try
  1960. {
  1961. // attempt exact case match first
  1962. // then try match ignoring case
  1963. JsonProperty property = contract.Properties.GetClosestMatchProperty(memberName);
  1964. if (property == null)
  1965. {
  1966. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  1967. {
  1968. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, "Could not find member '{0}' on {1}".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType)), null);
  1969. }
  1970. if (Serializer._missingMemberHandling == MissingMemberHandling.Error)
  1971. {
  1972. throw JsonSerializationException.Create(reader, "Could not find member '{0}' on object of type '{1}'".FormatWith(CultureInfo.InvariantCulture, memberName, contract.UnderlyingType.Name));
  1973. }
  1974. if (!reader.Read())
  1975. {
  1976. break;
  1977. }
  1978. SetExtensionData(contract, member, reader, memberName, newObject);
  1979. continue;
  1980. }
  1981. if (property.Ignored || !ShouldDeserialize(reader, property, newObject))
  1982. {
  1983. if (!reader.Read())
  1984. {
  1985. break;
  1986. }
  1987. SetPropertyPresence(reader, property, propertiesPresence);
  1988. SetExtensionData(contract, member, reader, memberName, newObject);
  1989. }
  1990. else
  1991. {
  1992. if (property.PropertyContract == null)
  1993. {
  1994. property.PropertyContract = GetContractSafe(property.PropertyType);
  1995. }
  1996. JsonConverter propertyConverter = GetConverter(property.PropertyContract, property.Converter, contract, member);
  1997. if (!reader.ReadForType(property.PropertyContract, propertyConverter != null))
  1998. {
  1999. throw JsonSerializationException.Create(reader, "Unexpected end when setting {0}'s value.".FormatWith(CultureInfo.InvariantCulture, memberName));
  2000. }
  2001. SetPropertyPresence(reader, property, propertiesPresence);
  2002. // set extension data if property is ignored or readonly
  2003. if (!SetPropertyValue(property, propertyConverter, contract, member, reader, newObject))
  2004. {
  2005. SetExtensionData(contract, member, reader, memberName, newObject);
  2006. }
  2007. }
  2008. }
  2009. catch (Exception ex)
  2010. {
  2011. if (IsErrorHandled(newObject, contract, memberName, reader as IJsonLineInfo, reader.Path, ex))
  2012. {
  2013. HandleError(reader, true, initialDepth);
  2014. }
  2015. else
  2016. {
  2017. throw;
  2018. }
  2019. }
  2020. break;
  2021. }
  2022. case JsonToken.EndObject:
  2023. finished = true;
  2024. break;
  2025. case JsonToken.Comment:
  2026. // ignore
  2027. break;
  2028. default:
  2029. throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType);
  2030. }
  2031. } while (!finished && reader.Read());
  2032. if (!finished)
  2033. {
  2034. ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object.");
  2035. }
  2036. if (propertiesPresence != null)
  2037. {
  2038. foreach (KeyValuePair<JsonProperty, PropertyPresence> propertyPresence in propertiesPresence)
  2039. {
  2040. JsonProperty property = propertyPresence.Key;
  2041. PropertyPresence presence = propertyPresence.Value;
  2042. EndProcessProperty(newObject, reader, contract, initialDepth, property, presence, true);
  2043. }
  2044. }
  2045. OnDeserialized(reader, contract, newObject);
  2046. return newObject;
  2047. }
  2048. private bool ShouldDeserialize(JsonReader reader, JsonProperty property, object target)
  2049. {
  2050. if (property.ShouldDeserialize == null)
  2051. {
  2052. return true;
  2053. }
  2054. bool shouldDeserialize = property.ShouldDeserialize(target);
  2055. if (TraceWriter != null && TraceWriter.LevelFilter >= TraceLevel.Verbose)
  2056. {
  2057. TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(null, reader.Path, "ShouldDeserialize result for property '{0}' on {1}: {2}".FormatWith(CultureInfo.InvariantCulture, property.PropertyName, property.DeclaringType, shouldDeserialize)), null);
  2058. }
  2059. return shouldDeserialize;
  2060. }
  2061. private bool CheckPropertyName(JsonReader reader, string memberName)
  2062. {
  2063. if (Serializer.MetadataPropertyHandling == MetadataPropertyHandling.ReadAhead)
  2064. {
  2065. switch (memberName)
  2066. {
  2067. case JsonTypeReflector.IdPropertyName:
  2068. case JsonTypeReflector.RefPropertyName:
  2069. case JsonTypeReflector.TypePropertyName:
  2070. case JsonTypeReflector.ArrayValuesPropertyName:
  2071. reader.Skip();
  2072. return true;
  2073. }
  2074. }
  2075. return false;
  2076. }
  2077. private void SetExtensionData(JsonObjectContract contract, JsonProperty member, JsonReader reader, string memberName, object o)
  2078. {
  2079. if (contract.ExtensionDataSetter != null)
  2080. {
  2081. try
  2082. {
  2083. object value = ReadExtensionDataValue(contract, member, reader);
  2084. contract.ExtensionDataSetter(o, memberName, value);
  2085. }
  2086. catch (Exception ex)
  2087. {
  2088. throw JsonSerializationException.Create(reader, "Error setting value in extension data for type '{0}'.".FormatWith(CultureInfo.InvariantCulture, contract.UnderlyingType), ex);
  2089. }
  2090. }
  2091. else
  2092. {
  2093. reader.Skip();
  2094. }
  2095. }
  2096. private object ReadExtensionDataValue(JsonObjectContract contract, JsonProperty member, JsonReader reader)
  2097. {
  2098. object value;
  2099. if (contract.ExtensionDataIsJToken)
  2100. {
  2101. value = JToken.ReadFrom(reader);
  2102. }
  2103. else
  2104. {
  2105. value = CreateValueInternal(reader, null, null, null, contract, member, null);
  2106. }
  2107. return value;
  2108. }
  2109. private void EndProcessProperty(object newObject, JsonReader reader, JsonObjectContract contract, int initialDepth, JsonProperty property, PropertyPresence presence, bool setDefaultValue)
  2110. {
  2111. if (presence == PropertyPresence.None || presence == PropertyPresence.Null)
  2112. {
  2113. try
  2114. {
  2115. Required resolvedRequired = property.Ignored ? Required.Default : property._required ?? contract.ItemRequired ?? Required.Default;
  2116. switch (presence)
  2117. {
  2118. case PropertyPresence.None:
  2119. if (resolvedRequired == Required.AllowNull || resolvedRequired == Required.Always)
  2120. {
  2121. throw JsonSerializationException.Create(reader, "Required property '{0}' not found in JSON.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
  2122. }
  2123. if (setDefaultValue && !property.Ignored)
  2124. {
  2125. if (property.PropertyContract == null)
  2126. {
  2127. property.PropertyContract = GetContractSafe(property.PropertyType);
  2128. }
  2129. if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer._defaultValueHandling), DefaultValueHandling.Populate) && property.Writable)
  2130. {
  2131. property.ValueProvider.SetValue(newObject, EnsureType(reader, property.GetResolvedDefaultValue(), CultureInfo.InvariantCulture, property.PropertyContract, property.PropertyType));
  2132. }
  2133. }
  2134. break;
  2135. case PropertyPresence.Null:
  2136. if (resolvedRequired == Required.Always)
  2137. {
  2138. throw JsonSerializationException.Create(reader, "Required property '{0}' expects a value but got null.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
  2139. }
  2140. if (resolvedRequired == Required.DisallowNull)
  2141. {
  2142. throw JsonSerializationException.Create(reader, "Required property '{0}' expects a non-null value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
  2143. }
  2144. break;
  2145. }
  2146. }
  2147. catch (Exception ex)
  2148. {
  2149. if (IsErrorHandled(newObject, contract, property.PropertyName, reader as IJsonLineInfo, reader.Path, ex))
  2150. {
  2151. HandleError(reader, true, initialDepth);
  2152. }
  2153. else
  2154. {
  2155. throw;
  2156. }
  2157. }
  2158. }
  2159. }
  2160. private void SetPropertyPresence(JsonReader reader, JsonProperty property, Dictionary<JsonProperty, PropertyPresence> requiredProperties)
  2161. {
  2162. if (property != null && requiredProperties != null)
  2163. {
  2164. PropertyPresence propertyPresence;
  2165. switch (reader.TokenType)
  2166. {
  2167. case JsonToken.String:
  2168. propertyPresence = (CoerceEmptyStringToNull(property.PropertyType, property.PropertyContract, (string)reader.Value))
  2169. ? PropertyPresence.Null
  2170. : PropertyPresence.Value;
  2171. break;
  2172. case JsonToken.Null:
  2173. case JsonToken.Undefined:
  2174. propertyPresence = PropertyPresence.Null;
  2175. break;
  2176. default:
  2177. propertyPresence = PropertyPresence.Value;
  2178. break;
  2179. }
  2180. requiredProperties[property] = propertyPresence;
  2181. }
  2182. }
  2183. private void HandleError(JsonReader reader, bool readPastError, int initialDepth)
  2184. {
  2185. ClearErrorContext();
  2186. if (readPastError)
  2187. {
  2188. reader.Skip();
  2189. while (reader.Depth > initialDepth)
  2190. {
  2191. if (!reader.Read())
  2192. {
  2193. break;
  2194. }
  2195. }
  2196. }
  2197. }
  2198. }
  2199. }