| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- #region License
- // Copyright 2006 James Newton-King
- // http://www.newtonsoft.com
- //
- // Copyright 2007 Konstantin Triger <[email protected]>
- //
- // This work is licensed under the Creative Commons Attribution 2.5 License
- // http://creativecommons.org/licenses/by/2.5/
- //
- // You are free:
- // * to copy, distribute, display, and perform the work
- // * to make derivative works
- // * to make commercial use of the work
- //
- // Under the following conditions:
- // * For any reuse or distribution, you must make clear to others the license terms of this work.
- // * Any of these conditions can be waived if you get permission from the copyright holder.
- #endregion
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using System.Collections;
- using System.Reflection;
- using System.ComponentModel;
- using Newtonsoft.Json.Utilities;
- using System.Web.Script.Serialization;
- namespace Newtonsoft.Json
- {
- /// <summary>
- /// Specifies reference loop handling options for the <see cref="JsonWriter"/>.
- /// </summary>
- enum ReferenceLoopHandling
- {
- /// <summary>
- /// Throw a <see cref="JsonSerializationException"/> when a loop is encountered.
- /// </summary>
- Error = 0,
- /// <summary>
- /// Ignore loop references and do not serialize.
- /// </summary>
- Ignore = 1,
- /// <summary>
- /// Serialize loop references.
- /// </summary>
- Serialize = 2
- }
- /// <summary>
- /// Serializes and deserializes objects into and from the Json format.
- /// The <see cref="JsonSerializer"/> enables you to control how objects are encoded into Json.
- /// </summary>
- sealed class JsonSerializer
- {
- abstract class LazyDictionary : IDictionary<string, object>
- {
- #region IDictionary<string,object> Members
- void IDictionary<string, object>.Add (string key, object value) {
- throw new NotSupportedException ();
- }
- bool IDictionary<string, object>.ContainsKey (string key) {
- throw new NotSupportedException ();
- }
- ICollection<string> IDictionary<string, object>.Keys {
- get { throw new NotSupportedException (); }
- }
- bool IDictionary<string, object>.Remove (string key) {
- throw new NotSupportedException ();
- }
- bool IDictionary<string, object>.TryGetValue (string key, out object value) {
- throw new NotSupportedException ();
- }
- ICollection<object> IDictionary<string, object>.Values {
- get { throw new NotSupportedException (); }
- }
- object IDictionary<string, object>.this [string key] {
- get {
- throw new NotSupportedException ();
- }
- set {
- throw new NotSupportedException ();
- }
- }
- #endregion
- #region ICollection<KeyValuePair<string,object>> Members
- void ICollection<KeyValuePair<string, object>>.Add (KeyValuePair<string, object> item) {
- throw new NotSupportedException ();
- }
- void ICollection<KeyValuePair<string, object>>.Clear () {
- throw new NotSupportedException ();
- }
- bool ICollection<KeyValuePair<string, object>>.Contains (KeyValuePair<string, object> item) {
- throw new NotSupportedException ();
- }
- void ICollection<KeyValuePair<string, object>>.CopyTo (KeyValuePair<string, object> [] array, int arrayIndex) {
- throw new NotSupportedException ();
- }
- int ICollection<KeyValuePair<string, object>>.Count {
- get { throw new NotSupportedException (); }
- }
- bool ICollection<KeyValuePair<string, object>>.IsReadOnly {
- get { throw new NotSupportedException (); }
- }
- bool ICollection<KeyValuePair<string, object>>.Remove (KeyValuePair<string, object> item) {
- throw new NotSupportedException ();
- }
- #endregion
- #region IEnumerable<KeyValuePair<string,object>> Members
- IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator () {
- return GetEnumerator ();
- }
- protected abstract IEnumerator<KeyValuePair<string, object>> GetEnumerator ();
- #endregion
- #region IEnumerable Members
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {
- return ((IEnumerable<KeyValuePair<string, object>>) this).GetEnumerator ();
- }
- #endregion
- }
- sealed class DeserializerLazyDictionary : LazyDictionary
- {
- readonly JsonReader _reader;
- readonly JsonSerializer _serializer;
- public DeserializerLazyDictionary (JsonReader reader, JsonSerializer serializer) {
- _reader = reader;
- _serializer = serializer;
- }
- protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
- return _serializer.PopulateObject (_reader);
- }
- }
- sealed class SerializerLazyDictionary : LazyDictionary
- {
- readonly object _source;
- public SerializerLazyDictionary (object source) {
- _source = source;
- }
- protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
- foreach (MemberInfo member in ReflectionUtils.GetFieldsAndProperties (_source.GetType (), BindingFlags.Public | BindingFlags.Instance)) {
- if (ReflectionUtils.CanReadMemberValue (member) && !member.IsDefined (typeof (ScriptIgnoreAttribute), true))
- if (!ReflectionUtils.IsIndexedProperty (member))
- yield return new KeyValuePair<string, object> (member.Name, ReflectionUtils.GetMemberValue (member, _source));
- }
- }
- }
- private ReferenceLoopHandling _referenceLoopHandling;
- private int _level;
- readonly JavaScriptSerializer _context;
- /// <summary>
- /// Get or set how reference loops (e.g. a class referencing itself) is handled.
- /// </summary>
- public ReferenceLoopHandling ReferenceLoopHandling
- {
- get { return _referenceLoopHandling; }
- set
- {
- if (value < ReferenceLoopHandling.Error || value > ReferenceLoopHandling.Serialize)
- {
- throw new ArgumentOutOfRangeException("value");
- }
- _referenceLoopHandling = value;
- }
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="JsonSerializer"/> class.
- /// </summary>
- public JsonSerializer(JavaScriptSerializer context)
- {
- _context = context;
- _referenceLoopHandling = ReferenceLoopHandling.Error;
- }
- #region Deserialize
- public object Deserialize (TextReader reader) {
- return Deserialize (new JsonReader (reader));
- }
- /// <summary>
- /// Deserializes the Json structure contained by the specified <see cref="JsonReader"/>
- /// into an instance of the specified type.
- /// </summary>
- /// <param name="reader">The type of object to create.</param>
- /// <param name="objectType">The <see cref="Type"/> of object being deserialized.</param>
- /// <returns>The instance of <paramref name="objectType"/> being deserialized.</returns>
- object Deserialize (JsonReader reader)
- {
- if (!reader.Read())
- return null;
- return GetObject(reader);
- }
- private object GetObject (JsonReader reader/*, Type objectType*/) {
- _level++;
- object value;
- switch (reader.TokenType) {
- // populate a typed object or generic dictionary/array
- // depending upon whether an objectType was supplied
- case JsonToken.StartObject:
- //value = PopulateObject(reader/*, objectType*/);
- value = new DeserializerLazyDictionary (reader, this);
- break;
- case JsonToken.StartArray:
- value = PopulateList (reader/*, objectType*/);
- break;
- case JsonToken.Integer:
- case JsonToken.Float:
- case JsonToken.String:
- case JsonToken.Boolean:
- case JsonToken.Date:
- //value = EnsureType(reader.Value, objectType);
- value = reader.Value;
- break;
- case JsonToken.Constructor:
- value = reader.Value.ToString ();
- break;
- case JsonToken.Null:
- case JsonToken.Undefined:
- value = null;
- break;
- default:
- throw new JsonSerializationException ("Unexpected token whil deserializing object: " + reader.TokenType);
- }
- _level--;
- return value;
- }
- private IEnumerable<object> PopulateList(JsonReader reader/*, Type objectType*/)
- {
- while (reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.EndArray:
- yield break;
- case JsonToken.Comment:
- break;
- default:
- yield return GetObject(reader/*, elementType*/);
- break;
- }
- }
- throw new JsonSerializationException("Unexpected end when deserializing array.");
- }
- private IEnumerator<KeyValuePair<string, object>> PopulateObject (JsonReader reader/*, Type objectType*/)
- {
- while (reader.Read())
- {
- switch (reader.TokenType)
- {
- case JsonToken.PropertyName:
- string memberName = reader.Value.ToString();
- if (!reader.Read ())
- throw new JsonSerializationException (string.Format ("Unexpected end when setting {0}'s value.", memberName));
- yield return new KeyValuePair<string, object> (memberName, GetObject (reader));
- break;
- case JsonToken.EndObject:
- yield break;
- default:
- throw new JsonSerializationException("Unexpected token when deserializing object: " + reader.TokenType);
- }
- }
- throw new JsonSerializationException("Unexpected end when deserializing object.");
- }
- #endregion
- #region Serialize
- /// <summary>
- /// Serializes the specified <see cref="Object"/> and writes the Json structure
- /// to a <c>Stream</c> using the specified <see cref="TextWriter"/>.
- /// </summary>
- /// <param name="textWriter">The <see cref="TextWriter"/> used to write the Json structure.</param>
- /// <param name="value">The <see cref="Object"/> to serialize.</param>
- public void Serialize(TextWriter textWriter, object value)
- {
- Serialize(new JsonWriter(textWriter), value);
- }
- /// <summary>
- /// Serializes the specified <see cref="Object"/> and writes the Json structure
- /// to a <c>Stream</c> using the specified <see cref="JsonWriter"/>.
- /// </summary>
- /// <param name="jsonWriter">The <see cref="JsonWriter"/> used to write the Json structure.</param>
- /// <param name="value">The <see cref="Object"/> to serialize.</param>
- void Serialize(JsonWriter jsonWriter, object value)
- {
- SerializeValue(jsonWriter, value);
- }
- private void SerializeValue(JsonWriter writer, object value)
- {
- //JsonConverter converter;
- if (value == null) {
- writer.WriteNull ();
- }
- else {
- JavaScriptConverter jsconverter = _context.GetConverter (value.GetType ());
- if (jsconverter != null) {
- value = jsconverter.Serialize (value, _context);
- if (value == null) {
- writer.WriteNull ();
- return;
- }
- }
- Type valueType = value.GetType ();
- switch (Type.GetTypeCode (valueType)) {
- case TypeCode.String:
- writer.WriteValue ((string) value);
- break;
- case TypeCode.Char:
- writer.WriteValue ((char) value);
- break;
- case TypeCode.Boolean:
- writer.WriteValue ((bool) value);
- break;
- case TypeCode.SByte:
- writer.WriteValue ((sbyte) value);
- break;
- case TypeCode.Int16:
- writer.WriteValue ((short) value);
- break;
- case TypeCode.UInt16:
- writer.WriteValue ((ushort) value);
- break;
- case TypeCode.Int32:
- writer.WriteValue ((int) value);
- break;
- case TypeCode.Byte:
- writer.WriteValue ((byte) value);
- break;
- case TypeCode.UInt32:
- writer.WriteValue ((uint) value);
- break;
- case TypeCode.Int64:
- writer.WriteValue ((long) value);
- break;
- case TypeCode.UInt64:
- writer.WriteValue ((ulong) value);
- break;
- case TypeCode.Single:
- writer.WriteValue ((float) value);
- break;
- case TypeCode.Double:
- writer.WriteValue ((double) value);
- break;
- case TypeCode.DateTime:
- writer.WriteValue ((DateTime) value);
- break;
- case TypeCode.Decimal:
- writer.WriteValue ((decimal) value);
- break;
- default:
-
- ThrowOnReferenceLoop (writer, value);
- writer.SerializeStack.Push (value);
- try {
- if (value is IDictionary) {
- SerializeDictionary (writer, (IDictionary) value);
- }
- else if (value is IEnumerable) {
- SerializeEnumerable (writer, (IEnumerable) value);
- }
- else {
- TypeConverter converter = TypeDescriptor.GetConverter (valueType);
- // use the objectType's TypeConverter if it has one and can convert to a string
- if (converter != null) {
- if (!(converter is ComponentConverter) && converter.GetType () != typeof (TypeConverter)) {
- if (converter.CanConvertTo (typeof (string))) {
- writer.WriteValue (converter.ConvertToInvariantString (value));
- return;
- }
- }
- }
- SerializeDictionary (writer, new SerializerLazyDictionary (value));
- }
- }
- finally {
- object x = writer.SerializeStack.Pop ();
- if (x != value)
- throw new InvalidOperationException ("Serialization stack is corrupted");
- }
- break;
- }
- }
- }
- private void ThrowOnReferenceLoop (JsonWriter writer, object value)
- {
- switch (_referenceLoopHandling) {
- case ReferenceLoopHandling.Error:
- if (writer.SerializeStack.Contains (value))
- throw new JsonSerializationException ("Self referencing loop");
- break;
- case ReferenceLoopHandling.Ignore:
- // return from method
- return;
- case ReferenceLoopHandling.Serialize:
- // continue
- break;
- default:
- throw new InvalidOperationException (string.Format ("Unexpected ReferenceLoopHandling value: '{0}'", _referenceLoopHandling));
- }
- }
- private void SerializeEnumerable (JsonWriter writer, IEnumerable values) {
- writer.WriteStartArray ();
- foreach (object value in values)
- SerializeValue (writer, value);
- writer.WriteEndArray ();
- }
- private void SerializeDictionary(JsonWriter writer, IDictionary values)
- {
- writer.WriteStartObject();
- foreach (DictionaryEntry entry in values)
- SerializePair (writer, entry.Key.ToString (), entry.Value);
- writer.WriteEndObject();
- }
- private void SerializeDictionary (JsonWriter writer, IDictionary<string, object> values) {
- writer.WriteStartObject ();
- foreach (KeyValuePair<string, object> entry in values)
- SerializePair (writer, entry.Key, entry.Value);
- writer.WriteEndObject ();
- }
- private void SerializePair (JsonWriter writer, string key, object value) {
- writer.WritePropertyName (key);
- SerializeValue (writer, value);
- }
- #endregion
- }
- }
|