#nullable enable using System; using System.Collections.Generic; using System.Linq; using Swan.Collections; using Swan.Reflection; namespace Swan.Formatters { /// /// 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 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 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 Swan.Attributes; /// using 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, Boolean format = false, String? typeSpecifier = null, Boolean includeNonPublic = false, String[]? includedNames = null, params String[] excludedNames) => Serialize(obj, format, typeSpecifier, includeNonPublic, includedNames, excludedNames, null, JsonSerializerCase.None); /// /// 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. /// The json serializer case. /// /// A that represents the current object. /// public static String Serialize(Object? obj, Boolean format, String? typeSpecifier, Boolean includeNonPublic, String[]? includedNames, String[]? excludedNames, List? parentReferences, JsonSerializerCase jsonSerializerCase) { if(obj != null && (obj is String || Definitions.AllBasicValueTypes.Contains(obj.GetType()))) { return SerializePrimitiveValue(obj); } SerializerOptions options = new SerializerOptions(format, typeSpecifier, includedNames, GetExcludedNames(obj?.GetType(), excludedNames), includeNonPublic, parentReferences, jsonSerializerCase); return Serialize(obj, options); } /// /// Serializes the specified object using the SerializerOptions provided. /// /// The object. /// The options. /// /// A that represents the current object. /// public static String Serialize(Object? obj, SerializerOptions options) => 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 string. /// The json serializer case. /// /// Type of the current deserializes. /// /// /// The following code shows how to deserialize a JSON string into a Dictionary. /// /// using 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, JsonSerializerCase.None); /// } /// } /// public static Object? Deserialize(String? json, JsonSerializerCase jsonSerializerCase) => Converter.FromJsonResult(Deserializer.DeserializeInternal(json), jsonSerializerCase); /// /// 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 string. /// /// Type of the current deserializes. /// /// /// The following code shows how to deserialize a JSON string into a Dictionary. /// /// using 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) => Deserialize(json, JsonSerializerCase.None); #endregion #region Private API private static String[]? GetExcludedNames(Type? type, String[]? excludedNames) { if(type == null) { return excludedNames; } IEnumerable excludedByAttr = IgnoredPropertiesCache.Retrieve(type, t => t.GetProperties().Where(x => AttributeCache.DefaultCache.Value.RetrieveOne(x)?.Ignored == true).Select(x => x.Name)); return excludedByAttr?.Any() != true ? excludedNames : excludedNames?.Any(String.IsNullOrWhiteSpace) == true ? excludedByAttr.Intersect(excludedNames.Where(y => !String.IsNullOrWhiteSpace(y))).ToArray() : excludedByAttr.ToArray(); } private static String SerializePrimitiveValue(Object obj) => obj switch { String stringValue => stringValue, Boolean boolValue => boolValue ? TrueLiteral : FalseLiteral, _ => obj.ToString()! }; #endregion } }