Skip to content

Instantly share code, notes, and snippets.

@niikoo
Last active October 12, 2020 08:58
Show Gist options
  • Save niikoo/7d08c3f3fd78ee11d1e84694f6d67938 to your computer and use it in GitHub Desktop.
Save niikoo/7d08c3f3fd78ee11d1e84694f6d67938 to your computer and use it in GitHub Desktop.
using System;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Faktum.Ics.Library.Utilities.Json
{
/// <inheritdoc />
/// <summary>
/// Defaults enum to the default value (first element). Can be overridden by setting an int as default value.
/// <example>
/// </example>
/// [JsonConverter(typeof(TolerantJsonEnumConverter), (int) Unknown)]
/// public enum Colors
/// {
/// Red = 0,
/// Blue,
/// Green,
/// Unknown
/// }
/// </summary>
public class TolerantJsonEnumConverter : StringEnumConverter
{
/// <summary>
/// The default value used to fallback on when a enum is not convertable.
/// </summary>
private readonly int _defaultValue;
/// <inheritdoc />
/// <summary>
/// Default constructor. Defaults the default value to 0.
/// </summary>
public TolerantJsonEnumConverter()
{
}
/// <inheritdoc />
/// <summary>
/// Sets the default value for the enum value.
/// </summary>
/// <param name="defaultValue">The default value to use.</param>
public TolerantJsonEnumConverter(int defaultValue)
{
_defaultValue = defaultValue;
}
/// <inheritdoc />
/// <summary>
/// Reads the provided JSON and attempts to convert using StringEnumConverter. If that fails set the value to the default value.
/// </summary>
/// <param name="reader">Reads the JSON value.</param>
/// <param name="objectType">Current type that is being converted.</param>
/// <param name="existingValue">The existing value being read.</param>
/// <param name="serializer">Instance of the JSON Serializer.</param>
/// <returns>The deserialized value of the enum if it exists or the default value if it does not.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var nonNullableType = objectType.IsNullable() ? objectType.GetNonNullable() : objectType;
try
{
return base.ReadJson(reader, nonNullableType, existingValue, serializer);
}
catch
{
return Enum.Parse(objectType, $"{_defaultValue}");
}
}
/// <inheritdoc />
/// <summary>
/// Validates that this converter can handle the type that is being provided.
/// </summary>
/// <param name="objectType">The type of the object being converted.</param>
/// <returns>True if the base class says so, and if the value is an enum and has a default value to fall on.</returns>
public override bool CanConvert(Type objectType)
{
var nonNullableType = objectType.IsNullable() ? objectType.GetNonNullable() : objectType;
return base.CanConvert(nonNullableType) && nonNullableType.GetTypeInfo().IsEnum && Enum.IsDefined(nonNullableType, _defaultValue);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment