JsonSerializer.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. #region License
  2. // Copyright 2006 James Newton-King
  3. // http://www.newtonsoft.com
  4. //
  5. // Copyright 2007 Konstantin Triger <[email protected]>
  6. //
  7. // This work is licensed under the Creative Commons Attribution 2.5 License
  8. // http://creativecommons.org/licenses/by/2.5/
  9. //
  10. // You are free:
  11. // * to copy, distribute, display, and perform the work
  12. // * to make derivative works
  13. // * to make commercial use of the work
  14. //
  15. // Under the following conditions:
  16. // * For any reuse or distribution, you must make clear to others the license terms of this work.
  17. // * Any of these conditions can be waived if you get permission from the copyright holder.
  18. #endregion
  19. using System;
  20. using System.Collections.Generic;
  21. using System.Text;
  22. using System.IO;
  23. using System.Collections;
  24. using System.Reflection;
  25. using System.ComponentModel;
  26. using Newtonsoft.Json.Utilities;
  27. using System.Web.Script.Serialization;
  28. namespace Newtonsoft.Json
  29. {
  30. /// <summary>
  31. /// Specifies reference loop handling options for the <see cref="JsonWriter"/>.
  32. /// </summary>
  33. enum ReferenceLoopHandling
  34. {
  35. /// <summary>
  36. /// Throw a <see cref="JsonSerializationException"/> when a loop is encountered.
  37. /// </summary>
  38. Error = 0,
  39. /// <summary>
  40. /// Ignore loop references and do not serialize.
  41. /// </summary>
  42. Ignore = 1,
  43. /// <summary>
  44. /// Serialize loop references.
  45. /// </summary>
  46. Serialize = 2
  47. }
  48. /// <summary>
  49. /// Serializes and deserializes objects into and from the Json format.
  50. /// The <see cref="JsonSerializer"/> enables you to control how objects are encoded into Json.
  51. /// </summary>
  52. sealed class JsonSerializer
  53. {
  54. sealed class LazyDictionary : IDictionary<string, object>
  55. {
  56. readonly JsonReader _reader;
  57. readonly JsonSerializer _serializer;
  58. public LazyDictionary (JsonReader reader, JsonSerializer serializer) {
  59. _reader = reader;
  60. _serializer = serializer;
  61. }
  62. #region IDictionary<string,object> Members
  63. void IDictionary<string, object>.Add (string key, object value) {
  64. throw new NotSupportedException ();
  65. }
  66. bool IDictionary<string, object>.ContainsKey (string key) {
  67. throw new Exception ("The method or operation is not implemented.");
  68. }
  69. ICollection<string> IDictionary<string, object>.Keys {
  70. get { throw new NotSupportedException (); }
  71. }
  72. bool IDictionary<string, object>.Remove (string key) {
  73. throw new NotSupportedException ();
  74. }
  75. bool IDictionary<string, object>.TryGetValue (string key, out object value) {
  76. throw new NotSupportedException ();
  77. }
  78. ICollection<object> IDictionary<string, object>.Values {
  79. get { throw new NotSupportedException (); }
  80. }
  81. object IDictionary<string, object>.this [string key] {
  82. get {
  83. throw new NotSupportedException ();
  84. }
  85. set {
  86. throw new NotSupportedException ();
  87. }
  88. }
  89. #endregion
  90. #region ICollection<KeyValuePair<string,object>> Members
  91. void ICollection<KeyValuePair<string, object>>.Add (KeyValuePair<string, object> item) {
  92. throw new NotSupportedException ();
  93. }
  94. void ICollection<KeyValuePair<string, object>>.Clear () {
  95. throw new NotSupportedException ();
  96. }
  97. bool ICollection<KeyValuePair<string, object>>.Contains (KeyValuePair<string, object> item) {
  98. throw new NotSupportedException ();
  99. }
  100. void ICollection<KeyValuePair<string, object>>.CopyTo (KeyValuePair<string, object> [] array, int arrayIndex) {
  101. throw new NotSupportedException ();
  102. }
  103. int ICollection<KeyValuePair<string, object>>.Count {
  104. get { throw new NotSupportedException (); }
  105. }
  106. bool ICollection<KeyValuePair<string, object>>.IsReadOnly {
  107. get { throw new NotSupportedException (); }
  108. }
  109. bool ICollection<KeyValuePair<string, object>>.Remove (KeyValuePair<string, object> item) {
  110. throw new NotSupportedException ();
  111. }
  112. #endregion
  113. #region IEnumerable<KeyValuePair<string,object>> Members
  114. IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator () {
  115. return _serializer.PopulateObject (_reader);
  116. }
  117. #endregion
  118. #region IEnumerable Members
  119. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {
  120. return ((IEnumerable<KeyValuePair<string,object>>)this).GetEnumerator();
  121. }
  122. #endregion
  123. }
  124. private ReferenceLoopHandling _referenceLoopHandling;
  125. private int _level;
  126. /// <summary>
  127. /// Get or set how reference loops (e.g. a class referencing itself) is handled.
  128. /// </summary>
  129. public ReferenceLoopHandling ReferenceLoopHandling
  130. {
  131. get { return _referenceLoopHandling; }
  132. set
  133. {
  134. if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
  135. {
  136. throw new ArgumentOutOfRangeException("value");
  137. }
  138. _referenceLoopHandling = value;
  139. }
  140. }
  141. /// <summary>
  142. /// Initializes a new instance of the <see cref="JsonSerializer"/> class.
  143. /// </summary>
  144. public JsonSerializer()
  145. {
  146. _referenceLoopHandling = ReferenceLoopHandling.Error;
  147. }
  148. #region Deserialize
  149. public object Deserialize (TextReader reader) {
  150. return Deserialize (new JsonReader (reader));
  151. }
  152. /// <summary>
  153. /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
  154. /// into an instance of the specified type.
  155. /// </summary>
  156. /// <param name="reader">The type of object to create.</param>
  157. /// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
  158. /// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
  159. object Deserialize (JsonReader reader)
  160. {
  161. if (!reader.Read())
  162. return null;
  163. return GetObject(reader);
  164. }
  165. private object GetObject (JsonReader reader/*, Type objectType*/) {
  166. _level++;
  167. object value;
  168. switch (reader.TokenType) {
  169. // populate a typed object or generic dictionary/array
  170. // depending upon whether an objectType was supplied
  171. case JsonToken.StartObject:
  172. //value = PopulateObject(reader/*, objectType*/);
  173. value = new LazyDictionary (reader, this);
  174. break;
  175. case JsonToken.StartArray:
  176. value = PopulateList (reader/*, objectType*/);
  177. break;
  178. case JsonToken.Integer:
  179. case JsonToken.Float:
  180. case JsonToken.String:
  181. case JsonToken.Boolean:
  182. case JsonToken.Date:
  183. //value = EnsureType(reader.Value, objectType);
  184. value = reader.Value;
  185. break;
  186. case JsonToken.Constructor:
  187. value = reader.Value.ToString ();
  188. break;
  189. case JsonToken.Null:
  190. case JsonToken.Undefined:
  191. value = null;
  192. break;
  193. default:
  194. throw new JsonSerializationException ("Unexpected token whil deserializing object: " + reader.TokenType);
  195. }
  196. _level--;
  197. return value;
  198. }
  199. private IEnumerable<object> PopulateList(JsonReader reader/*, Type objectType*/)
  200. {
  201. while (reader.Read())
  202. {
  203. switch (reader.TokenType)
  204. {
  205. case JsonToken.EndArray:
  206. yield break;
  207. case JsonToken.Comment:
  208. break;
  209. default:
  210. yield return GetObject(reader/*, elementType*/);
  211. break;
  212. }
  213. }
  214. throw new JsonSerializationException("Unexpected end when deserializing array.");
  215. }
  216. private IEnumerator<KeyValuePair<string, object>> PopulateObject (JsonReader reader/*, Type objectType*/)
  217. {
  218. while (reader.Read())
  219. {
  220. switch (reader.TokenType)
  221. {
  222. case JsonToken.PropertyName:
  223. string memberName = reader.Value.ToString();
  224. if (!reader.Read ())
  225. throw new JsonSerializationException (string.Format ("Unexpected end when setting {0}'s value.", memberName));
  226. yield return new KeyValuePair<string, object> (memberName, GetObject (reader));
  227. break;
  228. case JsonToken.EndObject:
  229. yield break;
  230. default:
  231. throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
  232. }
  233. }
  234. throw new JsonSerializationException("Unexpected end when deserializing object.");
  235. }
  236. #endregion
  237. #region Serialize
  238. /// <summary>
  239. /// Serializes the specified <see cref="Object"/> and writes the Json structure
  240. /// to a <c>Stream</c> using the specified <see cref="TextWriter"/>.
  241. /// </summary>
  242. /// <param name="textWriter">The <see cref="TextWriter"/> used to write the Json structure.</param>
  243. /// <param name="value">The <see cref="Object"/> to serialize.</param>
  244. public void Serialize(TextWriter textWriter, object value)
  245. {
  246. Serialize(new JsonWriter(textWriter), value);
  247. }
  248. /// <summary>
  249. /// Serializes the specified <see cref="Object"/> and writes the Json structure
  250. /// to a <c>Stream</c> using the specified <see cref="JsonWriter"/>.
  251. /// </summary>
  252. /// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the Json structure.</param>
  253. /// <param name="value">The <see cref="Object"/> to serialize.</param>
  254. void Serialize(JsonWriter jsonWriter, object value)
  255. {
  256. SerializeValue(jsonWriter, value);
  257. }
  258. private void SerializeValue(JsonWriter writer, object value)
  259. {
  260. //JsonConverter converter;
  261. if (value == null) {
  262. writer.WriteNull ();
  263. }
  264. else {
  265. switch (Type.GetTypeCode (value.GetType ())) {
  266. case TypeCode.String:
  267. writer.WriteValue ((string) value);
  268. break;
  269. case TypeCode.Char:
  270. writer.WriteValue ((char) value);
  271. break;
  272. case TypeCode.Boolean:
  273. writer.WriteValue ((bool) value);
  274. break;
  275. case TypeCode.SByte:
  276. writer.WriteValue ((sbyte) value);
  277. break;
  278. case TypeCode.Int16:
  279. writer.WriteValue ((short) value);
  280. break;
  281. case TypeCode.UInt16:
  282. writer.WriteValue ((ushort) value);
  283. break;
  284. case TypeCode.Int32:
  285. writer.WriteValue ((int) value);
  286. break;
  287. case TypeCode.Byte:
  288. writer.WriteValue ((byte) value);
  289. break;
  290. case TypeCode.UInt32:
  291. writer.WriteValue ((uint) value);
  292. break;
  293. case TypeCode.Int64:
  294. writer.WriteValue ((long) value);
  295. break;
  296. case TypeCode.UInt64:
  297. writer.WriteValue ((ulong) value);
  298. break;
  299. case TypeCode.Single:
  300. writer.WriteValue ((float) value);
  301. break;
  302. case TypeCode.Double:
  303. writer.WriteValue ((double) value);
  304. break;
  305. case TypeCode.DateTime:
  306. writer.WriteValue ((DateTime) value);
  307. break;
  308. case TypeCode.Decimal:
  309. writer.WriteValue ((decimal) value);
  310. break;
  311. default:
  312. if (value is IDictionary) {
  313. SerializeDictionary (writer, (IDictionary) value);
  314. }
  315. else if (value is IEnumerable) {
  316. SerializeEnumerable (writer, (IEnumerable) value);
  317. }
  318. else
  319. SerializeObject (writer, value);
  320. break;
  321. }
  322. }
  323. }
  324. private void WriteMemberInfoProperty(JsonWriter writer, object value, MemberInfo member)
  325. {
  326. if (!ReflectionUtils.IsIndexedProperty(member))
  327. {
  328. object memberValue = ReflectionUtils.GetMemberValue(member, value);
  329. if (writer.SerializeStack.Contains(memberValue))
  330. {
  331. switch (_referenceLoopHandling)
  332. {
  333. case ReferenceLoopHandling.Error:
  334. throw new JsonSerializationException("Self referencing loop");
  335. case ReferenceLoopHandling.Ignore:
  336. // return from method
  337. return;
  338. case ReferenceLoopHandling.Serialize:
  339. // continue
  340. break;
  341. default:
  342. throw new InvalidOperationException(string.Format("Unexpected ReferenceLoopHandling value: '{0}'", _referenceLoopHandling));
  343. }
  344. }
  345. writer.WritePropertyName(member.Name);
  346. SerializeValue(writer, memberValue);
  347. }
  348. }
  349. private void SerializeObject(JsonWriter writer, object value)
  350. {
  351. Type objectType = value.GetType();
  352. TypeConverter converter = TypeDescriptor.GetConverter(objectType);
  353. // use the objectType's TypeConverter if it has one and can convert to a string
  354. if (converter != null)
  355. if (!(converter is ComponentConverter) && converter.GetType() != typeof(TypeConverter))
  356. {
  357. if (converter.CanConvertTo(typeof(string)))
  358. {
  359. writer.WriteValue(converter.ConvertToInvariantString(value));
  360. return;
  361. }
  362. }
  363. writer.SerializeStack.Push(value);
  364. writer.WriteStartObject();
  365. foreach (MemberInfo member in ReflectionUtils.GetFieldsAndProperties(objectType, BindingFlags.Public | BindingFlags.Instance))
  366. {
  367. if (ReflectionUtils.CanReadMemberValue (member) && !member.IsDefined (typeof (ScriptIgnoreAttribute), true))
  368. WriteMemberInfoProperty(writer, value, member);
  369. }
  370. writer.WriteEndObject();
  371. object x = writer.SerializeStack.Pop();
  372. if (x != value)
  373. throw new Exception ();
  374. }
  375. private void SerializeEnumerable (JsonWriter writer, IEnumerable values) {
  376. writer.WriteStartArray ();
  377. foreach (object value in values)
  378. SerializeValue (writer, value);
  379. writer.WriteEndArray ();
  380. }
  381. private void SerializeDictionary(JsonWriter writer, IDictionary values)
  382. {
  383. writer.WriteStartObject();
  384. foreach (DictionaryEntry entry in values)
  385. {
  386. writer.WritePropertyName(entry.Key.ToString());
  387. SerializeValue(writer, entry.Value);
  388. }
  389. writer.WriteEndObject();
  390. }
  391. #endregion
  392. }
  393. }