PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/Json45r7/Source/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs

https://bitbucket.org/wantstudios/bitbucketclient
C# | 704 lines | 552 code | 125 blank | 27 comment | 169 complexity | 0b85011acd27960a07c3e612c82293be MD5 | raw file
  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.ComponentModel;
  29. #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
  30. using System.Dynamic;
  31. #endif
  32. using System.Globalization;
  33. using System.Security;
  34. using Newtonsoft.Json.Linq;
  35. using Newtonsoft.Json.Utilities;
  36. using System.Runtime.Serialization;
  37. #if NET20
  38. using Newtonsoft.Json.Utilities.LinqBridge;
  39. #else
  40. using System.Linq;
  41. #endif
  42. namespace Newtonsoft.Json.Serialization
  43. {
  44. internal class JsonSerializerInternalWriter : JsonSerializerInternalBase
  45. {
  46. private readonly List<object> _serializeStack = new List<object>();
  47. private JsonSerializerProxy _internalSerializer;
  48. public JsonSerializerInternalWriter(JsonSerializer serializer)
  49. : base(serializer)
  50. {
  51. }
  52. public void Serialize(JsonWriter jsonWriter, object value)
  53. {
  54. if (jsonWriter == null)
  55. throw new ArgumentNullException("jsonWriter");
  56. SerializeValue(jsonWriter, value, GetContractSafe(value), null, null, null);
  57. }
  58. private JsonSerializerProxy GetInternalSerializer()
  59. {
  60. if (_internalSerializer == null)
  61. _internalSerializer = new JsonSerializerProxy(this);
  62. return _internalSerializer;
  63. }
  64. private JsonContract GetContractSafe(object value)
  65. {
  66. if (value == null)
  67. return null;
  68. return Serializer.ContractResolver.ResolveContract(value.GetType());
  69. }
  70. private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
  71. {
  72. if (contract.UnderlyingType == typeof (byte[]))
  73. {
  74. bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Objects, contract, member, containerContract, containerProperty);
  75. if (includeTypeDetails)
  76. {
  77. writer.WriteStartObject();
  78. WriteTypeProperty(writer, contract.CreatedType);
  79. writer.WritePropertyName(JsonTypeReflector.ValuePropertyName);
  80. writer.WriteValue(value);
  81. writer.WriteEndObject();
  82. return;
  83. }
  84. }
  85. writer.WriteValue(value);
  86. }
  87. private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
  88. {
  89. if (value == null)
  90. {
  91. writer.WriteNull();
  92. return;
  93. }
  94. JsonConverter converter;
  95. if ((((converter = (member != null) ? member.Converter : null) != null)
  96. || ((converter = (containerProperty != null) ? containerProperty.ItemConverter : null) != null)
  97. || ((converter = (containerContract != null) ? containerContract.ItemConverter : null) != null)
  98. || ((converter = valueContract.Converter) != null)
  99. || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null)
  100. || ((converter = valueContract.InternalConverter) != null))
  101. && converter.CanWrite)
  102. {
  103. SerializeConvertable(writer, converter, value, valueContract, containerContract, containerProperty);
  104. return;
  105. }
  106. switch (valueContract.ContractType)
  107. {
  108. case JsonContractType.Object:
  109. SerializeObject(writer, value, (JsonObjectContract)valueContract, member, containerContract, containerProperty);
  110. break;
  111. case JsonContractType.Array:
  112. JsonArrayContract arrayContract = (JsonArrayContract) valueContract;
  113. SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, containerContract, containerProperty);
  114. break;
  115. case JsonContractType.Primitive:
  116. SerializePrimitive(writer, value, (JsonPrimitiveContract)valueContract, member, containerContract, containerProperty);
  117. break;
  118. case JsonContractType.String:
  119. SerializeString(writer, value, (JsonStringContract)valueContract);
  120. break;
  121. case JsonContractType.Dictionary:
  122. JsonDictionaryContract dictionaryContract = (JsonDictionaryContract) valueContract;
  123. SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, containerContract, containerProperty);
  124. break;
  125. #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
  126. case JsonContractType.Dynamic:
  127. SerializeDynamic(writer, (IDynamicMetaObjectProvider)value, (JsonDynamicContract)valueContract, member, containerContract, containerProperty);
  128. break;
  129. #endif
  130. #if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
  131. case JsonContractType.Serializable:
  132. SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract, member, containerContract, containerProperty);
  133. break;
  134. #endif
  135. case JsonContractType.Linq:
  136. ((JToken) value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
  137. break;
  138. }
  139. }
  140. private bool? ResolveIsReference(JsonContract contract, JsonProperty property, JsonContainerContract collectionContract, JsonProperty containerProperty)
  141. {
  142. bool? isReference = null;
  143. // value could be coming from a dictionary or array and not have a property
  144. if (property != null)
  145. isReference = property.IsReference;
  146. if (isReference == null && containerProperty != null)
  147. isReference = containerProperty.ItemIsReference;
  148. if (isReference == null && collectionContract != null)
  149. isReference = collectionContract.ItemIsReference;
  150. if (isReference == null)
  151. isReference = contract.IsReference;
  152. return isReference;
  153. }
  154. private bool ShouldWriteReference(object value, JsonProperty property, JsonContract valueContract, JsonContainerContract collectionContract, JsonProperty containerProperty)
  155. {
  156. if (value == null)
  157. return false;
  158. if (valueContract.ContractType == JsonContractType.Primitive || valueContract.ContractType == JsonContractType.String)
  159. return false;
  160. bool? isReference = ResolveIsReference(valueContract, property, collectionContract, containerProperty);
  161. if (isReference == null)
  162. {
  163. if (valueContract.ContractType == JsonContractType.Array)
  164. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
  165. else
  166. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  167. }
  168. if (!isReference.Value)
  169. return false;
  170. return Serializer.ReferenceResolver.IsReferenced(this, value);
  171. }
  172. private bool ShouldWriteProperty(object memberValue, JsonProperty property)
  173. {
  174. if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore &&
  175. memberValue == null)
  176. return false;
  177. if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
  178. && MiscellaneousUtils.ValueEquals(memberValue, property.DefaultValue))
  179. return false;
  180. return true;
  181. }
  182. private bool CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
  183. {
  184. if (value == null || contract.ContractType == JsonContractType.Primitive || contract.ContractType == JsonContractType.String)
  185. return true;
  186. ReferenceLoopHandling? referenceLoopHandling = null;
  187. if (property != null)
  188. referenceLoopHandling = property.ReferenceLoopHandling;
  189. if (referenceLoopHandling == null && containerProperty != null)
  190. referenceLoopHandling = containerProperty.ItemReferenceLoopHandling;
  191. if (referenceLoopHandling == null && containerContract != null)
  192. referenceLoopHandling = containerContract.ItemReferenceLoopHandling;
  193. if (_serializeStack.IndexOf(value) != -1)
  194. {
  195. switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling))
  196. {
  197. case ReferenceLoopHandling.Error:
  198. string message = "Self referencing loop detected";
  199. if (property != null)
  200. message += " for property '{0}'".FormatWith(CultureInfo.InvariantCulture, property.PropertyName);
  201. message += " with type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType());
  202. throw JsonSerializationException.Create(null, writer.ContainerPath, message, null);
  203. case ReferenceLoopHandling.Ignore:
  204. return false;
  205. case ReferenceLoopHandling.Serialize:
  206. return true;
  207. default:
  208. throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, Serializer.ReferenceLoopHandling));
  209. }
  210. }
  211. return true;
  212. }
  213. private void WriteReference(JsonWriter writer, object value)
  214. {
  215. writer.WriteStartObject();
  216. writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
  217. writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, value));
  218. writer.WriteEndObject();
  219. }
  220. internal static bool TryConvertToString(object value, Type type, out string s)
  221. {
  222. #if !(PocketPC || NETFX_CORE || PORTABLE)
  223. TypeConverter converter = ConvertUtils.GetConverter(type);
  224. // use the objectType's TypeConverter if it has one and can convert to a string
  225. if (converter != null
  226. #if !SILVERLIGHT
  227. && !(converter is ComponentConverter)
  228. #endif
  229. && converter.GetType() != typeof(TypeConverter))
  230. {
  231. if (converter.CanConvertTo(typeof(string)))
  232. {
  233. #if !SILVERLIGHT
  234. s = converter.ConvertToInvariantString(value);
  235. #else
  236. s = converter.ConvertToString(value);
  237. #endif
  238. return true;
  239. }
  240. }
  241. #endif
  242. #if SILVERLIGHT || PocketPC || NETFX_CORE
  243. if (value is Guid || value is Uri || value is TimeSpan)
  244. {
  245. s = value.ToString();
  246. return true;
  247. }
  248. #endif
  249. if (value is Type)
  250. {
  251. s = ((Type)value).AssemblyQualifiedName;
  252. return true;
  253. }
  254. s = null;
  255. return false;
  256. }
  257. private void SerializeString(JsonWriter writer, object value, JsonStringContract contract)
  258. {
  259. contract.InvokeOnSerializing(value, Serializer.Context);
  260. string s;
  261. TryConvertToString(value, contract.UnderlyingType, out s);
  262. writer.WriteValue(s);
  263. contract.InvokeOnSerialized(value, Serializer.Context);
  264. }
  265. private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  266. {
  267. contract.InvokeOnSerializing(value, Serializer.Context);
  268. _serializeStack.Add(value);
  269. WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty);
  270. int initialDepth = writer.Top;
  271. foreach (JsonProperty property in contract.Properties)
  272. {
  273. try
  274. {
  275. if (!property.Ignored && property.Readable && ShouldSerialize(property, value) && IsSpecified(property, value))
  276. {
  277. if (property.PropertyContract == null)
  278. property.PropertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
  279. object memberValue = property.ValueProvider.GetValue(value);
  280. JsonContract memberContract = (property.PropertyContract.UnderlyingType.IsSealed()) ? property.PropertyContract : GetContractSafe(memberValue);
  281. if (ShouldWriteProperty(memberValue, property))
  282. {
  283. string propertyName = property.PropertyName;
  284. if (ShouldWriteReference(memberValue, property, memberContract, contract, member))
  285. {
  286. writer.WritePropertyName(propertyName);
  287. WriteReference(writer, memberValue);
  288. continue;
  289. }
  290. if (!CheckForCircularReference(writer, memberValue, property, memberContract, contract, member))
  291. continue;
  292. if (memberValue == null)
  293. {
  294. Required resolvedRequired = property._required ?? contract.ItemRequired ?? Required.Default;
  295. if (resolvedRequired == Required.Always)
  296. throw JsonSerializationException.Create(null, writer.ContainerPath, "Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName), null);
  297. }
  298. writer.WritePropertyName(propertyName);
  299. SerializeValue(writer, memberValue, memberContract, property, contract, member);
  300. }
  301. }
  302. }
  303. catch (Exception ex)
  304. {
  305. if (IsErrorHandled(value, contract, property.PropertyName, writer.ContainerPath, ex))
  306. HandleError(writer, initialDepth);
  307. else
  308. throw;
  309. }
  310. }
  311. writer.WriteEndObject();
  312. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  313. contract.InvokeOnSerialized(value, Serializer.Context);
  314. }
  315. private void WriteObjectStart(JsonWriter writer, object value, JsonContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  316. {
  317. writer.WriteStartObject();
  318. bool isReference = ResolveIsReference(contract, member, collectionContract, containerProperty) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  319. if (isReference)
  320. {
  321. writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
  322. writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, value));
  323. }
  324. if (ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionContract, containerProperty))
  325. {
  326. WriteTypeProperty(writer, contract.UnderlyingType);
  327. }
  328. }
  329. private void WriteTypeProperty(JsonWriter writer, Type type)
  330. {
  331. writer.WritePropertyName(JsonTypeReflector.TypePropertyName);
  332. writer.WriteValue(ReflectionUtils.GetTypeName(type, Serializer.TypeNameAssemblyFormat, Serializer.Binder));
  333. }
  334. private bool HasFlag(DefaultValueHandling value, DefaultValueHandling flag)
  335. {
  336. return ((value & flag) == flag);
  337. }
  338. private bool HasFlag(PreserveReferencesHandling value, PreserveReferencesHandling flag)
  339. {
  340. return ((value & flag) == flag);
  341. }
  342. private bool HasFlag(TypeNameHandling value, TypeNameHandling flag)
  343. {
  344. return ((value & flag) == flag);
  345. }
  346. private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract, JsonContainerContract collectionContract, JsonProperty containerProperty)
  347. {
  348. if (ShouldWriteReference(value, null, contract, collectionContract, containerProperty))
  349. {
  350. WriteReference(writer, value);
  351. }
  352. else
  353. {
  354. if (!CheckForCircularReference(writer, value, null, contract, collectionContract, containerProperty))
  355. return;
  356. _serializeStack.Add(value);
  357. converter.WriteJson(writer, value, GetInternalSerializer());
  358. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  359. }
  360. }
  361. private void SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  362. {
  363. contract.InvokeOnSerializing(values.UnderlyingCollection, Serializer.Context);
  364. _serializeStack.Add(values.UnderlyingCollection);
  365. bool hasWrittenMetadataObject = WriteStartArray(writer, values, contract, member, collectionContract, containerProperty);
  366. writer.WriteStartArray();
  367. int initialDepth = writer.Top;
  368. int index = 0;
  369. // note that an error in the IEnumerable won't be caught
  370. foreach (object value in values)
  371. {
  372. try
  373. {
  374. JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value);
  375. if (ShouldWriteReference(value, null, valueContract, contract, member))
  376. {
  377. WriteReference(writer, value);
  378. }
  379. else
  380. {
  381. if (CheckForCircularReference(writer, value, null, valueContract, contract, member))
  382. {
  383. SerializeValue(writer, value, valueContract, null, contract, member);
  384. }
  385. }
  386. }
  387. catch (Exception ex)
  388. {
  389. if (IsErrorHandled(values.UnderlyingCollection, contract, index, writer.ContainerPath, ex))
  390. HandleError(writer, initialDepth);
  391. else
  392. throw;
  393. }
  394. finally
  395. {
  396. index++;
  397. }
  398. }
  399. writer.WriteEndArray();
  400. if (hasWrittenMetadataObject)
  401. writer.WriteEndObject();
  402. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  403. contract.InvokeOnSerialized(values.UnderlyingCollection, Serializer.Context);
  404. }
  405. private bool WriteStartArray(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
  406. {
  407. bool isReference = ResolveIsReference(contract, member, containerContract, containerProperty) ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
  408. bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Arrays, contract, member, containerContract, containerProperty);
  409. bool writeMetadataObject = isReference || includeTypeDetails;
  410. if (writeMetadataObject)
  411. {
  412. writer.WriteStartObject();
  413. if (isReference)
  414. {
  415. writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
  416. writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, values.UnderlyingCollection));
  417. }
  418. if (includeTypeDetails)
  419. {
  420. WriteTypeProperty(writer, values.UnderlyingCollection.GetType());
  421. }
  422. writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
  423. }
  424. if (contract.ItemContract == null)
  425. contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.CollectionItemType ?? typeof (object));
  426. return writeMetadataObject;
  427. }
  428. #if !(SILVERLIGHT || NETFX_CORE || PORTABLE)
  429. #if !NET20
  430. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework", MessageId = "System.Security.SecuritySafeCriticalAttribute")]
  431. [SecuritySafeCritical]
  432. #endif
  433. private void SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  434. {
  435. if (!JsonTypeReflector.FullyTrusted)
  436. {
  437. throw JsonSerializationException.Create(null, writer.ContainerPath, @"Type '{0}' implements ISerializable but cannot be serialized using the ISerializable interface because the current application is not fully trusted and ISerializable can expose secure data.
  438. 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.".FormatWith(CultureInfo.InvariantCulture, value.GetType()), null);
  439. }
  440. contract.InvokeOnSerializing(value, Serializer.Context);
  441. _serializeStack.Add(value);
  442. WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty);
  443. SerializationInfo serializationInfo = new SerializationInfo(contract.UnderlyingType, new FormatterConverter());
  444. value.GetObjectData(serializationInfo, Serializer.Context);
  445. foreach (SerializationEntry serializationEntry in serializationInfo)
  446. {
  447. writer.WritePropertyName(serializationEntry.Name);
  448. SerializeValue(writer, serializationEntry.Value, GetContractSafe(serializationEntry.Value), null, null, member);
  449. }
  450. writer.WriteEndObject();
  451. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  452. contract.InvokeOnSerialized(value, Serializer.Context);
  453. }
  454. #endif
  455. #if !(NET35 || NET20 || WINDOWS_PHONE || PORTABLE)
  456. private void SerializeDynamic(JsonWriter writer, IDynamicMetaObjectProvider value, JsonDynamicContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  457. {
  458. contract.InvokeOnSerializing(value, Serializer.Context);
  459. _serializeStack.Add(value);
  460. WriteObjectStart(writer, value, contract, member, collectionContract, containerProperty);
  461. foreach (string memberName in value.GetDynamicMemberNames())
  462. {
  463. object memberValue;
  464. if (DynamicUtils.TryGetMember(value, memberName, out memberValue))
  465. {
  466. string resolvedPropertyName = (contract.PropertyNameResolver != null)
  467. ? contract.PropertyNameResolver(memberName)
  468. : memberName;
  469. writer.WritePropertyName(resolvedPropertyName);
  470. SerializeValue(writer, memberValue, GetContractSafe(memberValue), null, null, member);
  471. }
  472. }
  473. writer.WriteEndObject();
  474. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  475. contract.InvokeOnSerialized(value, Serializer.Context);
  476. }
  477. #endif
  478. private bool ShouldWriteType(TypeNameHandling typeNameHandlingFlag, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
  479. {
  480. TypeNameHandling resolvedTypeNameHandling =
  481. ((member != null) ? member.TypeNameHandling : null)
  482. ?? ((containerProperty != null) ? containerProperty.ItemTypeNameHandling : null)
  483. ?? ((containerContract != null) ? containerContract.ItemTypeNameHandling : null)
  484. ?? Serializer.TypeNameHandling;
  485. if (HasFlag(resolvedTypeNameHandling, typeNameHandlingFlag))
  486. return true;
  487. // instance type and the property's type's contract default type are different (no need to put the type in JSON because the type will be created by default)
  488. if (HasFlag(resolvedTypeNameHandling, TypeNameHandling.Auto))
  489. {
  490. if (member != null)
  491. {
  492. if (contract.UnderlyingType != member.PropertyContract.CreatedType)
  493. return true;
  494. }
  495. else if (containerContract != null && containerContract.ItemContract != null)
  496. {
  497. if (contract.UnderlyingType != containerContract.ItemContract.CreatedType)
  498. return true;
  499. }
  500. }
  501. return false;
  502. }
  503. private void SerializeDictionary(JsonWriter writer, IWrappedDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
  504. {
  505. contract.InvokeOnSerializing(values.UnderlyingDictionary, Serializer.Context);
  506. _serializeStack.Add(values.UnderlyingDictionary);
  507. WriteObjectStart(writer, values.UnderlyingDictionary, contract, member, collectionContract, containerProperty);
  508. if (contract.ItemContract == null)
  509. contract.ItemContract = Serializer.ContractResolver.ResolveContract(contract.DictionaryValueType ?? typeof(object));
  510. int initialDepth = writer.Top;
  511. // Mono Unity 3.0 fix
  512. IWrappedDictionary d = values;
  513. foreach (DictionaryEntry entry in d)
  514. {
  515. string propertyName = GetPropertyName(entry);
  516. propertyName = (contract.PropertyNameResolver != null)
  517. ? contract.PropertyNameResolver(propertyName)
  518. : propertyName;
  519. try
  520. {
  521. object value = entry.Value;
  522. JsonContract valueContract = contract.FinalItemContract ?? GetContractSafe(value);
  523. if (ShouldWriteReference(value, null, valueContract, contract, member))
  524. {
  525. writer.WritePropertyName(propertyName);
  526. WriteReference(writer, value);
  527. }
  528. else
  529. {
  530. if (!CheckForCircularReference(writer, value, null, valueContract, contract, member))
  531. continue;
  532. writer.WritePropertyName(propertyName);
  533. SerializeValue(writer, value, valueContract, null, contract, member);
  534. }
  535. }
  536. catch (Exception ex)
  537. {
  538. if (IsErrorHandled(values.UnderlyingDictionary, contract, propertyName, writer.ContainerPath, ex))
  539. HandleError(writer, initialDepth);
  540. else
  541. throw;
  542. }
  543. }
  544. writer.WriteEndObject();
  545. _serializeStack.RemoveAt(_serializeStack.Count - 1);
  546. contract.InvokeOnSerialized(values.UnderlyingDictionary, Serializer.Context);
  547. }
  548. private string GetPropertyName(DictionaryEntry entry)
  549. {
  550. string propertyName;
  551. if (ConvertUtils.IsConvertible(entry.Key))
  552. return Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
  553. else if (TryConvertToString(entry.Key, entry.Key.GetType(), out propertyName))
  554. return propertyName;
  555. else
  556. return entry.Key.ToString();
  557. }
  558. private void HandleError(JsonWriter writer, int initialDepth)
  559. {
  560. ClearErrorContext();
  561. while (writer.Top > initialDepth)
  562. {
  563. writer.WriteEnd();
  564. }
  565. }
  566. private bool ShouldSerialize(JsonProperty property, object target)
  567. {
  568. if (property.ShouldSerialize == null)
  569. return true;
  570. return property.ShouldSerialize(target);
  571. }
  572. private bool IsSpecified(JsonProperty property, object target)
  573. {
  574. if (property.GetIsSpecified == null)
  575. return true;
  576. return property.GetIsSpecified(target);
  577. }
  578. }
  579. }