Skip to content

Commit

Permalink
Add a NoMemberFoundBehavior parameter to the converter. (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytro-khmara committed May 18, 2022
1 parent 0602027 commit ca3fbce
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace StrEnum.System.Text.Json.Converters;

public enum NoMemberFoundBehavior
{
ThrowException,
ReturnNull
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ namespace StrEnum.System.Text.Json.Converters;
/// <typeparam name="TStringEnum"></typeparam>
public class StringEnumJsonConverter<TStringEnum>: JsonConverter<TStringEnum> where TStringEnum: StringEnum<TStringEnum>, new()
{
private readonly NoMemberFoundBehavior _noMemberFoundBehavior;

public StringEnumJsonConverter(NoMemberFoundBehavior noMemberFoundBehavior)
{
_noMemberFoundBehavior = noMemberFoundBehavior;
}
public override TStringEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var jsonValue = reader.GetString();
Expand All @@ -17,6 +23,9 @@ public override TStringEnum Read(ref Utf8JsonReader reader, Type typeToConvert,

if (parsed == null || !((string)parsed).Equals(jsonValue, StringComparison.InvariantCulture))
{
if (_noMemberFoundBehavior == NoMemberFoundBehavior.ReturnNull)
return null!;

throw new JsonException($"Requested name or value '{jsonValue}' was not found in the string enum '{typeof(TStringEnum).Name}'.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ namespace StrEnum.System.Text.Json.Converters;

internal class StringEnumJsonConverterFactory : JsonConverterFactory
{
private readonly NoMemberFoundBehavior _noMemberFoundBehavior;

public StringEnumJsonConverterFactory(NoMemberFoundBehavior noMemberFoundBehavior)
{
_noMemberFoundBehavior = noMemberFoundBehavior;
}

private readonly ConcurrentDictionary<Type, JsonConverter> _converters = new();

public override bool CanConvert(Type typeToConvert)
Expand All @@ -27,7 +34,7 @@ private JsonConverter BuildConverter(Type stringEnum)
{
var converterType = typeof(StringEnumJsonConverter<>).MakeGenericType(stringEnum);

var converter = Activator.CreateInstance(converterType) as JsonConverter;
var converter = Activator.CreateInstance(converterType, _noMemberFoundBehavior) as JsonConverter;

return converter!;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ public static class JsonSerializerOptionsExtensions
/// Configure System.Text.Json to serialize and deserialize string enums.
/// </summary>
/// <param name="options"></param>
/// <param name="noMemberFoundBehavior">Specifies whether to thrown an exception or use a null value for members that cannot be parsed.</param>
/// <returns></returns>
public static JsonSerializerOptions UseStringEnums(this JsonSerializerOptions options)
public static JsonSerializerOptions UseStringEnums(this JsonSerializerOptions options, NoMemberFoundBehavior noMemberFoundBehavior = NoMemberFoundBehavior.ThrowException)
{
options.Converters.Add(new StringEnumJsonConverterFactory());
options.Converters.Add(new StringEnumJsonConverterFactory(noMemberFoundBehavior));

return options;
}
Expand Down
18 changes: 16 additions & 2 deletions test/StrEnum.System.Text.Json.IntegrationTests/DeserializeTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json;
using FluentAssertions;
using StrEnum.System.Text.Json.Converters;
using Xunit;

namespace StrEnum.System.Text.Json.IntegrationTests
Expand Down Expand Up @@ -30,7 +31,7 @@ public void Deserialize_GivenJsonWithEnumsValue_ShouldDeserializesItWithValidEnu
}

[Fact]
public void Deserialize_GivenJsonWithEnumsName_ShouldThrowAnException()
public void Deserialize_GivenJsonWithEnumsName_AndDefaultNoMemberBehavior_ShouldThrowAnException()
{
var json = @"{""sport"":""TrailRunning""}";

Expand All @@ -57,7 +58,7 @@ public void Deserialize_GivenJsonWithNull_ShouldDeserializesItWithNull()
}

[Fact]
public void Deserialize_GivenJsonWithInvalidValue_ShouldThrowAnException()
public void Deserialize_GivenJsonWithInvalidValue_AndDefaultNoMemberBehavior_ShouldThrowAnException()
{
var json = @"{""sport"":""Quidditch""}";

Expand All @@ -69,5 +70,18 @@ public void Deserialize_GivenJsonWithInvalidValue_ShouldThrowAnException()
deserialize.Should().Throw<JsonException>()
.WithMessage("Requested name or value 'Quidditch' was not found in the string enum 'Sport'.");
}

[Fact]
public void Deserialize_GivenJsonWithInvalidValue_AndReturnNullNoMemberBehavior_ShouldThrowAnException()
{
var json = @"{""sport"":""Quidditch""}";

var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }
.UseStringEnums(NoMemberFoundBehavior.ReturnNull);

var obj = JsonSerializer.Deserialize<DeserializedObject>(json, options);

obj.Should().BeEquivalentTo(new { Sport = (Sport?)null });
}
}
}

0 comments on commit ca3fbce

Please sign in to comment.