PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Services/NGngoo/Gngoo.Core/Json/Serialization/JsonSerializerInternalWriter.cs

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