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