namespace Unosquare.Swan.Formatters { using Reflection; using System; using Components; using System.Collections.Generic; using System.Linq; using System.Reflection; using Attributes; /// /// A very simple, light-weight JSON library written by Mario /// to teach Geo how things are done /// /// This is an useful helper for small tasks but it doesn't represent a full-featured /// serializer such as the beloved Json.NET. /// public static partial class Json { #region Constants internal const string AddMethodName = "Add"; private const char OpenObjectChar = '{'; private const char CloseObjectChar = '}'; private const char OpenArrayChar = '['; private const char CloseArrayChar = ']'; private const char FieldSeparatorChar = ','; private const char ValueSeparatorChar = ':'; private const char StringEscapeChar = '\\'; private const char StringQuotedChar = '"'; private const string EmptyObjectLiteral = "{ }"; private const string EmptyArrayLiteral = "[ ]"; private const string TrueLiteral = "true"; private const string FalseLiteral = "false"; private const string NullLiteral = "null"; #endregion private static readonly PropertyTypeCache PropertyTypeCache = new PropertyTypeCache(); private static readonly FieldTypeCache FieldTypeCache = new FieldTypeCache(); private static readonly CollectionCacheRepository IgnoredPropertiesCache = new CollectionCacheRepository(); #region Public API /// /// Serializes the specified object into a JSON string. /// /// The object. /// if set to true it formats and indents the output. /// The type specifier. Leave null or empty to avoid setting. /// if set to true non-public getters will be also read. /// The included property names. /// The excluded property names. /// /// A that represents the current object. /// /// /// The following example describes how to serialize a simple object. /// /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// static void Main() /// { /// var obj = new { One = "One", Two = "Two" }; /// /// var serial = Json.Serialize(obj); // {"One": "One","Two": "Two"} /// } /// } /// /// The following example details how to serialize an object using the . /// /// using Unosquare.Swan.Attributes; /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// class JsonPropertyExample /// { /// [JsonProperty("data")] /// public string Data { get; set; } /// /// [JsonProperty("ignoredData", true)] /// public string IgnoredData { get; set; } /// } /// /// static void Main() /// { /// var obj = new JsonPropertyExample() { Data = "OK", IgnoredData = "OK" }; /// /// // {"data": "OK"} /// var serializedObj = Json.Serialize(obj); /// } /// } /// /// public static string Serialize( object obj, bool format = false, string typeSpecifier = null, bool includeNonPublic = false, string[] includedNames = null, string[] excludedNames = null) { return Serialize(obj, format, typeSpecifier, includeNonPublic, includedNames, excludedNames, null); } /// /// Serializes the specified object into a JSON string. /// /// The object. /// if set to true it formats and indents the output. /// The type specifier. Leave null or empty to avoid setting. /// if set to true non-public getters will be also read. /// The included property names. /// The excluded property names. /// The parent references. /// /// A that represents the current object. /// public static string Serialize( object obj, bool format, string typeSpecifier, bool includeNonPublic, string[] includedNames, string[] excludedNames, List parentReferences) { if (obj != null && (obj is string || Definitions.AllBasicValueTypes.Contains(obj.GetType()))) { return SerializePrimitiveValue(obj); } var options = new SerializerOptions( format, typeSpecifier, includedNames, GetExcludedNames(obj?.GetType(), excludedNames), includeNonPublic, parentReferences); return Serializer.Serialize(obj, 0, options); } /// /// Serializes the specified object only including the specified property names. /// /// The object. /// if set to true it formats and indents the output. /// The include names. /// A that represents the current object. /// /// The following example shows how to serialize a simple object including the specified properties. /// /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// static void Main() /// { /// // object to serialize /// var obj = new { One = "One", Two = "Two", Three = "Three" }; /// /// // the included names /// var includedNames = new[] { "Two", "Three" }; /// /// // serialize only the included names /// var data = Json.SerializeOnly(basicObject, true, includedNames); /// // {"Two": "Two","Three": "Three" } /// } /// } /// /// public static string SerializeOnly(object obj, bool format, params string[] includeNames) { var options = new SerializerOptions(format, null, includeNames); return Serializer.Serialize(obj, 0, options); } /// /// Serializes the specified object excluding the specified property names. /// /// The object. /// if set to true it formats and indents the output. /// The exclude names. /// A that represents the current object. /// /// The following code shows how to serialize a simple object exluding the specified properties. /// /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// static void Main() /// { /// // object to serialize /// var obj = new { One = "One", Two = "Two", Three = "Three" }; /// /// // the excluded names /// var excludeNames = new[] { "Two", "Three" }; /// /// // serialize excluding /// var data = Json.SerializeExcluding(basicObject, false, includedNames); /// // {"One": "One"} /// } /// } /// /// public static string SerializeExcluding(object obj, bool format, params string[] excludeNames) { var options = new SerializerOptions(format, null, null, excludeNames); return Serializer.Serialize(obj, 0, options); } /// /// Deserializes the specified json string as either a Dictionary[string, object] or as a List[object] /// depending on the syntax of the JSON string. /// /// The json. /// Type of the current deserializes. /// /// The following code shows how to deserialize a JSON string into a Dictionary. /// /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// static void Main() /// { /// // json to deserialize /// var basicJson = "{\"One\":\"One\",\"Two\":\"Two\",\"Three\":\"Three\"}"; /// /// // deserializes the specified json into a Dictionary<string, object>. /// var data = Json.Deserialize(basicJson); /// } /// } /// /// public static object Deserialize(string json) => Deserializer.DeserializeInternal(json); /// /// Deserializes the specified json string and converts it to the specified object type. /// Non-public constructors and property setters are ignored. /// /// The type of object to deserialize. /// The json. /// The deserialized specified type object. /// /// The following code describes how to deserialize a JSON string into an object of type T. /// /// using Unosquare.Swan.Formatters; /// /// class Example /// { /// static void Main() /// { /// // json type BasicJson to serialize /// var basicJson = "{\"One\":\"One\",\"Two\":\"Two\",\"Three\":\"Three\"}"; /// /// // deserializes the specified string in a new instance of the type BasicJson. /// var data = Json.Deserialize<BasicJson>(basicJson); /// } /// } /// /// public static T Deserialize(string json) => (T)Deserialize(json, typeof(T)); /// /// Deserializes the specified json string and converts it to the specified object type. /// /// The type of object to deserialize. /// The json. /// if set to true, it also uses the non-public constructors and property setters. /// The deserialized specified type object. public static T Deserialize(string json, bool includeNonPublic) => (T)Deserialize(json, typeof(T), includeNonPublic); /// /// Deserializes the specified json string and converts it to the specified object type. /// /// The json. /// Type of the result. /// if set to true, it also uses the non-public constructors and property setters. /// Type of the current conversion from json result. public static object Deserialize(string json, Type resultType, bool includeNonPublic = false) => Converter.FromJsonResult(Deserializer.DeserializeInternal(json), resultType, includeNonPublic); #endregion #region Private API private static string[] GetExcludedNames(Type type, string[] excludedNames) { if (type == null) return excludedNames; var excludedByAttr = IgnoredPropertiesCache.Retrieve(type, t => t.GetProperties() .Where(x => Runtime.AttributeCache.RetrieveOne(x)?.Ignored == true) .Select(x => x.Name)); if (excludedByAttr?.Any() != true) return excludedNames; return excludedNames == null ? excludedByAttr.ToArray() : excludedByAttr.Intersect(excludedNames).ToArray(); } private static string SerializePrimitiveValue(object obj) { switch (obj) { case string stringValue: return stringValue; case bool boolValue: return boolValue ? TrueLiteral : FalseLiteral; default: return obj.ToString(); } } #endregion } }