JsonSerializer.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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 internal class DeserializerLazyDictionary : JavaScriptSerializer.LazyDictionary
  55. {
  56. readonly JsonReader _reader;
  57. readonly JsonSerializer _serializer;
  58. IEnumerator<KeyValuePair<string, object>> _innerEnum;
  59. object _firstValue;
  60. public DeserializerLazyDictionary (JsonReader reader, JsonSerializer serializer) {
  61. _reader = reader;
  62. _serializer = serializer;
  63. }
  64. public object PeekFirst () {
  65. if (_innerEnum != null)
  66. throw new InvalidOperationException ("first already taken");
  67. _innerEnum = _serializer.PopulateObject (_reader);
  68. if (_innerEnum.MoveNext ())
  69. _firstValue = _innerEnum.Current;
  70. return _firstValue;
  71. }
  72. protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
  73. if (_innerEnum == null)
  74. _innerEnum = _serializer.PopulateObject (_reader);
  75. if (_firstValue != null)
  76. yield return (KeyValuePair<string, object>) _firstValue;
  77. while (_innerEnum.MoveNext ())
  78. yield return _innerEnum.Current;
  79. }
  80. }
  81. sealed class SerializerLazyDictionary : JavaScriptSerializer.LazyDictionary
  82. {
  83. readonly object _source;
  84. public SerializerLazyDictionary (object source) {
  85. _source = source;
  86. }
  87. protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
  88. foreach (MemberInfo member in ReflectionUtils.GetFieldsAndProperties (_source.GetType (), BindingFlags.Public | BindingFlags.Instance)) {
  89. if (ReflectionUtils.CanReadMemberValue (member) && !member.IsDefined (typeof (ScriptIgnoreAttribute), true))
  90. if (!ReflectionUtils.IsIndexedProperty (member))
  91. yield return new KeyValuePair<string, object> (member.Name, ReflectionUtils.GetMemberValue (member, _source));
  92. }
  93. }
  94. }
  95. sealed class GenericDictionaryLazyDictionary : JavaScriptSerializer.LazyDictionary
  96. {
  97. readonly object _source;
  98. readonly PropertyInfo _piKeys;
  99. readonly PropertyInfo _piValues;
  100. public GenericDictionaryLazyDictionary (object source, Type dictType) {
  101. _source = source;
  102. _piKeys = dictType.GetProperty ("Keys");
  103. _piValues = dictType.GetProperty ("Values");
  104. }
  105. protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
  106. IEnumerable eKeys = (IEnumerable) _piKeys.GetValue (_source, null);
  107. IEnumerator eValues = ((IEnumerable) _piValues.GetValue (_source, null)).GetEnumerator();
  108. foreach (object key in eKeys) {
  109. string keyString = key == null ? null : key.ToString ();
  110. if (!eValues.MoveNext ())
  111. throw new IndexOutOfRangeException (keyString);
  112. yield return new KeyValuePair<string, object> (keyString, eValues.Current);
  113. }
  114. if (eValues.MoveNext ())
  115. throw new IndexOutOfRangeException (eValues.Current != null ? eValues.Current.ToString () : String.Empty);
  116. }
  117. }
  118. private int _maxJsonLength;
  119. private int _recursionLimit;
  120. private int _currentRecursionCounter;
  121. private ReferenceLoopHandling _referenceLoopHandling;
  122. readonly JavaScriptSerializer _context;
  123. readonly JavaScriptTypeResolver _typeResolver;
  124. public int MaxJsonLength
  125. {
  126. get { return _maxJsonLength; }
  127. set { _maxJsonLength = value; }
  128. }
  129. public int RecursionLimit {
  130. get { return _recursionLimit; }
  131. set { _recursionLimit = value; }
  132. }
  133. /// <summary>
  134. /// Get or set how reference loops (e.g. a class referencing itself) is handled.
  135. /// </summary>
  136. public ReferenceLoopHandling ReferenceLoopHandling
  137. {
  138. get { return _referenceLoopHandling; }
  139. set
  140. {
  141. if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
  142. {
  143. throw new ArgumentOutOfRangeException("value");
  144. }
  145. _referenceLoopHandling = value;
  146. }
  147. }
  148. /// <summary>
  149. /// Initializes a new instance of the <see cref="JsonSerializer"/> class.
  150. /// </summary>
  151. public JsonSerializer(JavaScriptSerializer context, JavaScriptTypeResolver resolver)
  152. {
  153. _context = context;
  154. _typeResolver = resolver;
  155. _referenceLoopHandling = ReferenceLoopHandling.Error;
  156. }
  157. #region Deserialize
  158. public object Deserialize (TextReader reader) {
  159. return Deserialize (new JsonReader (reader, MaxJsonLength, RecursionLimit));
  160. }
  161. /// <summary>
  162. /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
  163. /// into an instance of the specified type.
  164. /// </summary>
  165. /// <param name="reader">The type of object to create.</param>
  166. /// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
  167. /// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
  168. object Deserialize (JsonReader reader)
  169. {
  170. if (!reader.Read())
  171. return null;
  172. return GetObject(reader);
  173. }
  174. private object GetObject (JsonReader reader/*, Type objectType*/) {
  175. if (RecursionLimit > 0 && reader.CurrentRecursionLevel >= RecursionLimit) {
  176. throw new ArgumentException ("RecursionLimit exceeded.");
  177. }
  178. object value;
  179. switch (reader.TokenType) {
  180. // populate a typed object or generic dictionary/array
  181. // depending upon whether an objectType was supplied
  182. case JsonToken.StartObject:
  183. //value = PopulateObject(reader/*, objectType*/);
  184. value = new DeserializerLazyDictionary (reader, this);
  185. break;
  186. case JsonToken.StartArray:
  187. value = PopulateList (reader/*, objectType*/);
  188. break;
  189. case JsonToken.Integer:
  190. case JsonToken.Float:
  191. case JsonToken.String:
  192. case JsonToken.Boolean:
  193. case JsonToken.Date:
  194. //value = EnsureType(reader.Value, objectType);
  195. value = reader.Value;
  196. break;
  197. case JsonToken.Constructor:
  198. value = reader.Value.ToString ();
  199. break;
  200. case JsonToken.Null:
  201. case JsonToken.Undefined:
  202. value = null;
  203. break;
  204. default:
  205. throw new JsonSerializationException ("Unexpected token whil deserializing object: " + reader.TokenType);
  206. }
  207. return value;
  208. }
  209. private IEnumerable<object> PopulateList(JsonReader reader/*, Type objectType*/)
  210. {
  211. while (reader.Read())
  212. {
  213. switch (reader.TokenType)
  214. {
  215. case JsonToken.EndArray:
  216. yield break;
  217. case JsonToken.Comment:
  218. break;
  219. default:
  220. yield return GetObject(reader/*, elementType*/);
  221. break;
  222. }
  223. }
  224. throw new JsonSerializationException("Unexpected end when deserializing array.");
  225. }
  226. private IEnumerator<KeyValuePair<string, object>> PopulateObject (JsonReader reader/*, Type objectType*/)
  227. {
  228. reader.IncrementRecursionLevel ();
  229. while (reader.Read ())
  230. {
  231. switch (reader.TokenType)
  232. {
  233. case JsonToken.PropertyName:
  234. string memberName = reader.Value.ToString();
  235. if (!reader.Read ())
  236. throw new JsonSerializationException (string.Format ("Unexpected end when setting {0}'s value.", memberName));
  237. yield return new KeyValuePair<string, object> (memberName, GetObject (reader));
  238. break;
  239. case JsonToken.EndObject:
  240. reader.DecrementRecursionLevel ();
  241. yield break;
  242. default:
  243. throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
  244. }
  245. }
  246. throw new JsonSerializationException("Unexpected end when deserializing object.");
  247. }
  248. #endregion
  249. #region Serialize
  250. /// <summary>
  251. /// Serializes the specified <see cref="Object"/> and writes the Json structure
  252. /// to a <c>Stream</c> using the specified <see cref="TextWriter"/>.
  253. /// </summary>
  254. /// <param name="textWriter">The <see cref="TextWriter"/> used to write the Json structure.</param>
  255. /// <param name="value">The <see cref="Object"/> to serialize.</param>
  256. public void Serialize(TextWriter textWriter, object value)
  257. {
  258. Serialize(new JsonWriter(textWriter, MaxJsonLength), value);
  259. }
  260. /// <summary>
  261. /// Serializes the specified <see cref="Object"/> and writes the Json structure
  262. /// to a <c>Stream</c> using the specified <see cref="JsonWriter"/>.
  263. /// </summary>
  264. /// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the Json structure.</param>
  265. /// <param name="value">The <see cref="Object"/> to serialize.</param>
  266. void Serialize(JsonWriter jsonWriter, object value)
  267. {
  268. SerializeValue(jsonWriter, value);
  269. }
  270. private void SerializeValue(JsonWriter writer, object value)
  271. {
  272. //JsonConverter converter;
  273. _currentRecursionCounter++;
  274. if (RecursionLimit > 0 && _currentRecursionCounter > RecursionLimit) {
  275. throw new ArgumentException ("RecursionLimit exceeded.");
  276. }
  277. if (value == null) {
  278. writer.WriteNull ();
  279. }
  280. else {
  281. JavaScriptConverter jsconverter = _context.GetConverter (value.GetType ());
  282. if (jsconverter != null) {
  283. value = jsconverter.Serialize (value, _context);
  284. if (value == null) {
  285. writer.WriteNull ();
  286. return;
  287. }
  288. }
  289. Type valueType = value.GetType ();
  290. switch (Type.GetTypeCode (valueType)) {
  291. case TypeCode.String:
  292. writer.WriteValue ((string) value);
  293. break;
  294. case TypeCode.Char:
  295. writer.WriteValue ((char) value);
  296. break;
  297. case TypeCode.Boolean:
  298. writer.WriteValue ((bool) value);
  299. break;
  300. case TypeCode.SByte:
  301. writer.WriteValue ((sbyte) value);
  302. break;
  303. case TypeCode.Int16:
  304. writer.WriteValue ((short) value);
  305. break;
  306. case TypeCode.UInt16:
  307. writer.WriteValue ((ushort) value);
  308. break;
  309. case TypeCode.Int32:
  310. writer.WriteValue ((int) value);
  311. break;
  312. case TypeCode.Byte:
  313. writer.WriteValue ((byte) value);
  314. break;
  315. case TypeCode.UInt32:
  316. writer.WriteValue ((uint) value);
  317. break;
  318. case TypeCode.Int64:
  319. writer.WriteValue ((long) value);
  320. break;
  321. case TypeCode.UInt64:
  322. writer.WriteValue ((ulong) value);
  323. break;
  324. case TypeCode.Single:
  325. writer.WriteValue ((float) value);
  326. break;
  327. case TypeCode.Double:
  328. writer.WriteValue ((double) value);
  329. break;
  330. case TypeCode.DateTime:
  331. writer.WriteValue ((DateTime) value);
  332. break;
  333. case TypeCode.Decimal:
  334. writer.WriteValue ((decimal) value);
  335. break;
  336. default:
  337. ThrowOnReferenceLoop (writer, value);
  338. writer.SerializeStack.Push (value);
  339. try {
  340. Type genDictType;
  341. if (value is IDictionary)
  342. SerializeDictionary (writer, (IDictionary) value);
  343. else if (value is IDictionary<string, object>)
  344. SerializeDictionary (writer, (IDictionary<string, object>) value, null);
  345. else if ((genDictType = ReflectionUtils.GetGenericDictionary (valueType)) != null)
  346. SerializeDictionary (writer, new GenericDictionaryLazyDictionary (value, genDictType), null);
  347. else if (value is IEnumerable) {
  348. SerializeEnumerable (writer, (IEnumerable) value);
  349. }
  350. else {
  351. SerializeCustomObject (writer, value, valueType);
  352. }
  353. }
  354. finally {
  355. object x = writer.SerializeStack.Pop ();
  356. if (x != value)
  357. throw new InvalidOperationException ("Serialization stack is corrupted");
  358. }
  359. break;
  360. }
  361. }
  362. _currentRecursionCounter--;
  363. }
  364. private void ThrowOnReferenceLoop (JsonWriter writer, object value)
  365. {
  366. switch (_referenceLoopHandling) {
  367. case ReferenceLoopHandling.Error:
  368. if (writer.SerializeStack.Contains (value))
  369. throw new JsonSerializationException ("Self referencing loop");
  370. break;
  371. case ReferenceLoopHandling.Ignore:
  372. // return from method
  373. return;
  374. case ReferenceLoopHandling.Serialize:
  375. // continue
  376. break;
  377. default:
  378. throw new InvalidOperationException (string.Format ("Unexpected ReferenceLoopHandling value: '{0}'", _referenceLoopHandling));
  379. }
  380. }
  381. private void SerializeEnumerable (JsonWriter writer, IEnumerable values) {
  382. writer.WriteStartArray ();
  383. foreach (object value in values)
  384. SerializeValue (writer, value);
  385. writer.WriteEndArray ();
  386. }
  387. private void SerializeDictionary(JsonWriter writer, IDictionary values)
  388. {
  389. writer.WriteStartObject();
  390. foreach (DictionaryEntry entry in values)
  391. SerializePair (writer, entry.Key.ToString (), entry.Value);
  392. writer.WriteEndObject();
  393. }
  394. private void SerializeDictionary (JsonWriter writer, IDictionary<string, object> values, string typeID) {
  395. writer.WriteStartObject ();
  396. if (typeID != null) {
  397. SerializePair (writer, JavaScriptSerializer.SerializedTypeNameKey, typeID);
  398. }
  399. foreach (KeyValuePair<string, object> entry in values)
  400. SerializePair (writer, entry.Key, entry.Value);
  401. writer.WriteEndObject ();
  402. }
  403. private void SerializeCustomObject (JsonWriter writer, object value, Type valueType)
  404. {
  405. if (value is Uri) {
  406. Uri uri = value as Uri;
  407. writer.WriteValue (uri.GetComponents (UriComponents.AbsoluteUri, UriFormat.UriEscaped));
  408. return;
  409. }
  410. if (valueType == typeof (Guid)) {
  411. writer.WriteValue (((Guid) value).ToString ());
  412. return;
  413. }
  414. string typeID = null;
  415. if (_typeResolver != null) {
  416. typeID = _typeResolver.ResolveTypeId (valueType);
  417. }
  418. SerializeDictionary (writer, new SerializerLazyDictionary (value), typeID);
  419. }
  420. private void SerializePair (JsonWriter writer, string key, object value) {
  421. writer.WritePropertyName (key);
  422. SerializeValue (writer, value);
  423. }
  424. #endregion
  425. }
  426. }