PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/Library/External/Newtonsoft.Json/Serialization/JsonSerializerInternalWriter.cs

http://github.com/sones/sones
C# | 506 lines | 400 code | 82 blank | 24 comment | 94 complexity | b6ca8311dab7257b475de2245b634e81 MD5 | raw file
Possible License(s): AGPL-3.0, Apache-2.0, LGPL-3.0
  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. using System.Globalization;
  30. using System.Linq;
  31. using System.Reflection;
  32. using Newtonsoft.Json.Linq;
  33. using Newtonsoft.Json.Utilities;
  34. using System.Runtime.Serialization;
  35. namespace Newtonsoft.Json.Serialization
  36. {
  37. internal class JsonSerializerInternalWriter : JsonSerializerInternalBase
  38. {
  39. private JsonSerializerProxy _internalSerializer;
  40. private List<object> _serializeStack;
  41. private List<object> SerializeStack
  42. {
  43. get
  44. {
  45. if (_serializeStack == null)
  46. _serializeStack = new List<object>();
  47. return _serializeStack;
  48. }
  49. }
  50. public JsonSerializerInternalWriter(JsonSerializer serializer) : base(serializer)
  51. {
  52. }
  53. public void Serialize(JsonWriter jsonWriter, object value)
  54. {
  55. if (jsonWriter == null)
  56. throw new ArgumentNullException("jsonWriter");
  57. SerializeValue(jsonWriter, value, null, GetContractSafe(value));
  58. }
  59. private JsonSerializerProxy GetInternalSerializer()
  60. {
  61. if (_internalSerializer == null)
  62. _internalSerializer = new JsonSerializerProxy(this);
  63. return _internalSerializer;
  64. }
  65. private JsonContract GetContractSafe(object value)
  66. {
  67. if (value == null)
  68. return null;
  69. return Serializer.ContractResolver.ResolveContract(value.GetType());
  70. }
  71. private void SerializeValue(JsonWriter writer, object value, JsonConverter memberConverter, JsonContract contract)
  72. {
  73. JsonConverter converter = memberConverter;
  74. if (value == null)
  75. {
  76. writer.WriteNull();
  77. return;
  78. }
  79. if (converter != null
  80. || Serializer.HasClassConverter(contract, out converter)
  81. || Serializer.HasMatchingConverter(contract.UnderlyingType, out converter))
  82. {
  83. SerializeConvertable(writer, converter, value, contract);
  84. }
  85. else if (contract is JsonPrimitiveContract)
  86. {
  87. writer.WriteValue(value);
  88. }
  89. else if (value is JToken)
  90. {
  91. ((JToken) value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
  92. }
  93. else if (contract is JsonObjectContract)
  94. {
  95. SerializeObject(writer, value, (JsonObjectContract) contract);
  96. }
  97. else if (contract is JsonDictionaryContract)
  98. {
  99. SerializeDictionary(writer, (IDictionary) value, (JsonDictionaryContract) contract);
  100. }
  101. else if (contract is JsonArrayContract)
  102. {
  103. if (value is IList)
  104. {
  105. SerializeList(writer, (IList) value, (JsonArrayContract) contract);
  106. }
  107. else if (value is IEnumerable)
  108. {
  109. SerializeEnumerable(writer, (IEnumerable) value, (JsonArrayContract) contract);
  110. }
  111. else
  112. {
  113. throw new Exception(
  114. "Cannot serialize '{0}' into a JSON array. Type does not implement IEnumerable.".FormatWith(
  115. CultureInfo.InvariantCulture, value.GetType()));
  116. }
  117. }
  118. }
  119. private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract)
  120. {
  121. if (value == null)
  122. return false;
  123. if (contract is JsonPrimitiveContract)
  124. return false;
  125. bool? isReference = null;
  126. // value could be coming from a dictionary or array and not have a property
  127. if (property != null)
  128. isReference = property.IsReference;
  129. if (isReference == null)
  130. isReference = contract.IsReference;
  131. if (isReference == null)
  132. {
  133. if (value is IList)
  134. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
  135. else if (value is IDictionary)
  136. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  137. else if (value is IEnumerable)
  138. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
  139. else
  140. isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  141. }
  142. if (!isReference.Value)
  143. return false;
  144. return Serializer.ReferenceResolver.IsReferenced(value);
  145. }
  146. private void WriteMemberInfoProperty(JsonWriter writer, object value, object memberValue, JsonProperty property, JsonContract contract)
  147. {
  148. string propertyName = property.PropertyName;
  149. JsonConverter memberConverter = property.MemberConverter;
  150. object defaultValue = property.DefaultValue;
  151. if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore &&
  152. memberValue == null)
  153. return;
  154. if (property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling) ==
  155. DefaultValueHandling.Ignore && Equals(memberValue, defaultValue))
  156. return;
  157. if (ShouldWriteReference(memberValue, property, contract))
  158. {
  159. writer.WritePropertyName(propertyName);
  160. WriteReference(writer, memberValue);
  161. return;
  162. }
  163. if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling))
  164. return;
  165. writer.WritePropertyName(propertyName);
  166. SerializeValue(writer, memberValue, memberConverter, contract);
  167. }
  168. private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling)
  169. {
  170. if (SerializeStack.IndexOf(value) != -1)
  171. {
  172. switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling))
  173. {
  174. case ReferenceLoopHandling.Error:
  175. throw new JsonSerializationException("Self referencing loop");
  176. case ReferenceLoopHandling.Ignore:
  177. return false;
  178. case ReferenceLoopHandling.Serialize:
  179. return true;
  180. default:
  181. throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, Serializer.ReferenceLoopHandling));
  182. }
  183. }
  184. return true;
  185. }
  186. private void WriteReference(JsonWriter writer, object value)
  187. {
  188. writer.WriteStartObject();
  189. writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
  190. writer.WriteValue(Serializer.ReferenceResolver.GetReference(value));
  191. writer.WriteEndObject();
  192. }
  193. internal static bool TryConvertToString(object value, Type type, out string s)
  194. {
  195. #if !PocketPC
  196. TypeConverter converter = ConvertUtils.GetConverter(type);
  197. // use the objectType's TypeConverter if it has one and can convert to a string
  198. if (converter != null
  199. #if !SILVERLIGHT
  200. && !(converter is ComponentConverter)
  201. #endif
  202. && (converter.GetType() != typeof(TypeConverter) || value is Type))
  203. {
  204. if (converter.CanConvertTo(typeof(string)))
  205. {
  206. #if !SILVERLIGHT
  207. s = converter.ConvertToInvariantString(value);
  208. #else
  209. s = converter.ConvertToString(value);
  210. #endif
  211. return true;
  212. }
  213. }
  214. #endif
  215. #if SILVERLIGHT || PocketPC
  216. if (value is Guid || value is Type || value is Uri || value is TimeSpan)
  217. {
  218. s = value.ToString();
  219. return true;
  220. }
  221. #endif
  222. s = null;
  223. return false;
  224. }
  225. private void SerializeObject(JsonWriter writer, object value, JsonObjectContract contract)
  226. {
  227. contract.InvokeOnSerializing(value);
  228. string s;
  229. if (TryConvertToString(value, contract.UnderlyingType, out s))
  230. {
  231. writer.WriteValue(s);
  232. contract.InvokeOnSerialized(value);
  233. return;
  234. }
  235. SerializeStack.Add(value);
  236. writer.WriteStartObject();
  237. bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  238. if (isReference)
  239. {
  240. writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
  241. writer.WriteValue(Serializer.ReferenceResolver.GetReference(value));
  242. }
  243. if (HasFlag(Serializer.TypeNameHandling, TypeNameHandling.Objects))
  244. {
  245. WriteTypeProperty(writer, contract.UnderlyingType);
  246. }
  247. int initialDepth = writer.Top;
  248. foreach (JsonProperty property in contract.Properties)
  249. {
  250. try
  251. {
  252. if (!property.Ignored && property.Readable)
  253. {
  254. object memberValue = property.ValueProvider.GetValue(value);
  255. JsonContract memberContract = GetContractSafe(memberValue);
  256. WriteMemberInfoProperty(writer, value, memberValue, property, memberContract);
  257. }
  258. }
  259. catch (Exception ex)
  260. {
  261. if (IsErrorHandled(value, contract, property.PropertyName, ex))
  262. HandleError(writer, initialDepth);
  263. else
  264. throw;
  265. }
  266. }
  267. writer.WriteEndObject();
  268. SerializeStack.RemoveAt(SerializeStack.Count - 1);
  269. contract.InvokeOnSerialized(value);
  270. }
  271. private void WriteTypeProperty(JsonWriter writer, Type type)
  272. {
  273. writer.WritePropertyName(JsonTypeReflector.TypePropertyName);
  274. writer.WriteValue(type.AssemblyQualifiedName);
  275. }
  276. private bool HasFlag(PreserveReferencesHandling value, PreserveReferencesHandling flag)
  277. {
  278. return ((value & flag) == flag);
  279. }
  280. private bool HasFlag(TypeNameHandling value, TypeNameHandling flag)
  281. {
  282. return ((value & flag) == flag);
  283. }
  284. private void SerializeConvertable(JsonWriter writer, JsonConverter converter, object value, JsonContract contract)
  285. {
  286. if (ShouldWriteReference(value, null, contract))
  287. {
  288. WriteReference(writer, value);
  289. }
  290. else
  291. {
  292. if (!CheckForCircularReference(value, null))
  293. return;
  294. SerializeStack.Add(value);
  295. converter.WriteJson(writer, value, GetInternalSerializer());
  296. SerializeStack.RemoveAt(SerializeStack.Count - 1);
  297. }
  298. }
  299. private void SerializeEnumerable(JsonWriter writer, IEnumerable values, JsonArrayContract contract)
  300. {
  301. SerializeList(writer, values.Cast<object>().ToList(), contract);
  302. }
  303. private void SerializeList(JsonWriter writer, IList values, JsonArrayContract contract)
  304. {
  305. contract.InvokeOnSerializing(values);
  306. SerializeStack.Add(values);
  307. bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
  308. bool includeTypeDetails = HasFlag(Serializer.TypeNameHandling, TypeNameHandling.Arrays);
  309. if (isReference || includeTypeDetails)
  310. {
  311. writer.WriteStartObject();
  312. if (isReference)
  313. {
  314. writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
  315. writer.WriteValue(Serializer.ReferenceResolver.GetReference(values));
  316. }
  317. if (includeTypeDetails)
  318. {
  319. WriteTypeProperty(writer, values.GetType());
  320. }
  321. writer.WritePropertyName(JsonTypeReflector.ArrayValuesPropertyName);
  322. }
  323. writer.WriteStartArray();
  324. int initialDepth = writer.Top;
  325. for (int i = 0; i < values.Count; i++)
  326. {
  327. try
  328. {
  329. object value = values[i];
  330. JsonContract valueContract = GetContractSafe(value);
  331. if (ShouldWriteReference(value, null, valueContract))
  332. {
  333. WriteReference(writer, value);
  334. }
  335. else
  336. {
  337. if (!CheckForCircularReference(value, null))
  338. continue;
  339. SerializeValue(writer, value, null, valueContract);
  340. }
  341. }
  342. catch (Exception ex)
  343. {
  344. if (IsErrorHandled(values, contract, i, ex))
  345. HandleError(writer, initialDepth);
  346. else
  347. throw;
  348. }
  349. }
  350. writer.WriteEndArray();
  351. if (isReference || includeTypeDetails)
  352. {
  353. writer.WriteEndObject();
  354. }
  355. SerializeStack.RemoveAt(SerializeStack.Count - 1);
  356. contract.InvokeOnSerialized(values);
  357. }
  358. private void SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract)
  359. {
  360. contract.InvokeOnSerializing(values);
  361. SerializeStack.Add(values);
  362. writer.WriteStartObject();
  363. bool isReference = contract.IsReference ?? HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
  364. if (isReference)
  365. {
  366. writer.WritePropertyName(JsonTypeReflector.IdPropertyName);
  367. writer.WriteValue(Serializer.ReferenceResolver.GetReference(values));
  368. }
  369. if (HasFlag(Serializer.TypeNameHandling, TypeNameHandling.Objects))
  370. {
  371. WriteTypeProperty(writer, values.GetType());
  372. }
  373. int initialDepth = writer.Top;
  374. foreach (DictionaryEntry entry in values)
  375. {
  376. string propertyName = GetPropertyName(entry);
  377. try
  378. {
  379. object value = entry.Value;
  380. JsonContract valueContract = GetContractSafe(value);
  381. if (ShouldWriteReference(value, null, valueContract))
  382. {
  383. writer.WritePropertyName(propertyName);
  384. WriteReference(writer, value);
  385. }
  386. else
  387. {
  388. if (!CheckForCircularReference(value, null))
  389. continue;
  390. writer.WritePropertyName(propertyName);
  391. SerializeValue(writer, value, null, valueContract);
  392. }
  393. }
  394. catch (Exception ex)
  395. {
  396. if (IsErrorHandled(values, contract, propertyName, ex))
  397. HandleError(writer, initialDepth);
  398. else
  399. throw;
  400. }
  401. }
  402. writer.WriteEndObject();
  403. SerializeStack.RemoveAt(SerializeStack.Count - 1);
  404. contract.InvokeOnSerialized(values);
  405. }
  406. private string GetPropertyName(DictionaryEntry entry)
  407. {
  408. string propertyName;
  409. if (entry.Key is IConvertible)
  410. return Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
  411. else if (TryConvertToString(entry.Key, entry.Key.GetType(), out propertyName))
  412. return propertyName;
  413. throw new JsonSerializationException("Could not create string property name from type '{0}'.".FormatWith(CultureInfo.InvariantCulture, entry.Key.GetType()));
  414. }
  415. private void HandleError(JsonWriter writer, int initialDepth)
  416. {
  417. ClearErrorContext();
  418. while (writer.Top > initialDepth)
  419. {
  420. writer.WriteEnd();
  421. }
  422. }
  423. }
  424. }