JsonSerializer.cs 13 KB

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