211 lines
8.4 KiB
C#
211 lines
8.4 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Swan.Collections;
|
|
using Swan.Reflection;
|
|
|
|
namespace Swan.Formatters {
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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<String> IgnoredPropertiesCache = new CollectionCacheRepository<global::System.String>();
|
|
|
|
#region Public API
|
|
|
|
/// <summary>
|
|
/// Serializes the specified object into a JSON string.
|
|
/// </summary>
|
|
/// <param name="obj">The object.</param>
|
|
/// <param name="format">if set to <c>true</c> it formats and indents the output.</param>
|
|
/// <param name="typeSpecifier">The type specifier. Leave null or empty to avoid setting.</param>
|
|
/// <param name="includeNonPublic">if set to <c>true</c> non-public getters will be also read.</param>
|
|
/// <param name="includedNames">The included property names.</param>
|
|
/// <param name="excludedNames">The excluded property names.</param>
|
|
/// <returns>
|
|
/// A <see cref="System.String" /> that represents the current object.
|
|
/// </returns>
|
|
/// <example>
|
|
/// The following example describes how to serialize a simple object.
|
|
/// <code>
|
|
/// using Swan.Formatters;
|
|
///
|
|
/// class Example
|
|
/// {
|
|
/// static void Main()
|
|
/// {
|
|
/// var obj = new { One = "One", Two = "Two" };
|
|
///
|
|
/// var serial = Json.Serialize(obj); // {"One": "One","Two": "Two"}
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
///
|
|
/// The following example details how to serialize an object using the <see cref="JsonPropertyAttribute"/>.
|
|
///
|
|
/// <code>
|
|
/// 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);
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
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);
|
|
|
|
/// <summary>
|
|
/// Serializes the specified object into a JSON string.
|
|
/// </summary>
|
|
/// <param name="obj">The object.</param>
|
|
/// <param name="format">if set to <c>true</c> it formats and indents the output.</param>
|
|
/// <param name="typeSpecifier">The type specifier. Leave null or empty to avoid setting.</param>
|
|
/// <param name="includeNonPublic">if set to <c>true</c> non-public getters will be also read.</param>
|
|
/// <param name="includedNames">The included property names.</param>
|
|
/// <param name="excludedNames">The excluded property names.</param>
|
|
/// <param name="parentReferences">The parent references.</param>
|
|
/// <param name="jsonSerializerCase">The json serializer case.</param>
|
|
/// <returns>
|
|
/// A <see cref="System.String" /> that represents the current object.
|
|
/// </returns>
|
|
public static String Serialize(Object? obj, Boolean format, String? typeSpecifier, Boolean includeNonPublic, String[]? includedNames, String[]? excludedNames, List<WeakReference>? 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Serializes the specified object using the SerializerOptions provided.
|
|
/// </summary>
|
|
/// <param name="obj">The object.</param>
|
|
/// <param name="options">The options.</param>
|
|
/// <returns>
|
|
/// A <see cref="String" /> that represents the current object.
|
|
/// </returns>
|
|
public static String Serialize(Object? obj, SerializerOptions options) => Serializer.Serialize(obj, 0, options);
|
|
|
|
/// <summary>
|
|
/// Deserializes the specified json string as either a Dictionary[string, object] or as a List[object]
|
|
/// depending on the syntax of the JSON string.
|
|
/// </summary>
|
|
/// <param name="json">The JSON string.</param>
|
|
/// <param name="jsonSerializerCase">The json serializer case.</param>
|
|
/// <returns>
|
|
/// Type of the current deserializes.
|
|
/// </returns>
|
|
/// <example>
|
|
/// The following code shows how to deserialize a JSON string into a Dictionary.
|
|
/// <code>
|
|
/// 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);
|
|
/// }
|
|
/// }
|
|
/// </code></example>
|
|
public static Object? Deserialize(String? json, JsonSerializerCase jsonSerializerCase) => Converter.FromJsonResult(Deserializer.DeserializeInternal(json), jsonSerializerCase);
|
|
|
|
/// <summary>
|
|
/// Deserializes the specified json string as either a Dictionary[string, object] or as a List[object]
|
|
/// depending on the syntax of the JSON string.
|
|
/// </summary>
|
|
/// <param name="json">The JSON string.</param>
|
|
/// <returns>
|
|
/// Type of the current deserializes.
|
|
/// </returns>
|
|
/// <example>
|
|
/// The following code shows how to deserialize a JSON string into a Dictionary.
|
|
/// <code>
|
|
/// 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);
|
|
/// }
|
|
/// }
|
|
/// </code></example>
|
|
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<global::System.String> excludedByAttr = IgnoredPropertiesCache.Retrieve(type, t => t.GetProperties().Where(x => AttributeCache.DefaultCache.Value.RetrieveOne<JsonPropertyAttribute>(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
|
|
}
|
|
}
|