Skip to content

Commit ca3fbce

Browse files
Add a NoMemberFoundBehavior parameter to the converter. (#2)
1 parent 0602027 commit ca3fbce

5 files changed

Lines changed: 43 additions & 5 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace StrEnum.System.Text.Json.Converters;
2+
3+
public enum NoMemberFoundBehavior
4+
{
5+
ThrowException,
6+
ReturnNull
7+
}

src/StrEnum.System.Text.Json/Converters/StringEnumJsonConverter.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ namespace StrEnum.System.Text.Json.Converters;
99
/// <typeparam name="TStringEnum"></typeparam>
1010
public class StringEnumJsonConverter<TStringEnum>: JsonConverter<TStringEnum> where TStringEnum: StringEnum<TStringEnum>, new()
1111
{
12+
private readonly NoMemberFoundBehavior _noMemberFoundBehavior;
13+
14+
public StringEnumJsonConverter(NoMemberFoundBehavior noMemberFoundBehavior)
15+
{
16+
_noMemberFoundBehavior = noMemberFoundBehavior;
17+
}
1218
public override TStringEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1319
{
1420
var jsonValue = reader.GetString();
@@ -17,6 +23,9 @@ public override TStringEnum Read(ref Utf8JsonReader reader, Type typeToConvert,
1723

1824
if (parsed == null || !((string)parsed).Equals(jsonValue, StringComparison.InvariantCulture))
1925
{
26+
if (_noMemberFoundBehavior == NoMemberFoundBehavior.ReturnNull)
27+
return null!;
28+
2029
throw new JsonException($"Requested name or value '{jsonValue}' was not found in the string enum '{typeof(TStringEnum).Name}'.");
2130
}
2231

src/StrEnum.System.Text.Json/Converters/StringEnumJsonConverterFactory.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ namespace StrEnum.System.Text.Json.Converters;
66

77
internal class StringEnumJsonConverterFactory : JsonConverterFactory
88
{
9+
private readonly NoMemberFoundBehavior _noMemberFoundBehavior;
10+
11+
public StringEnumJsonConverterFactory(NoMemberFoundBehavior noMemberFoundBehavior)
12+
{
13+
_noMemberFoundBehavior = noMemberFoundBehavior;
14+
}
15+
916
private readonly ConcurrentDictionary<Type, JsonConverter> _converters = new();
1017

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

30-
var converter = Activator.CreateInstance(converterType) as JsonConverter;
37+
var converter = Activator.CreateInstance(converterType, _noMemberFoundBehavior) as JsonConverter;
3138

3239
return converter!;
3340
}

src/StrEnum.System.Text.Json/JsonSerializerOptionsExtensions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ public static class JsonSerializerOptionsExtensions
99
/// Configure System.Text.Json to serialize and deserialize string enums.
1010
/// </summary>
1111
/// <param name="options"></param>
12+
/// <param name="noMemberFoundBehavior">Specifies whether to thrown an exception or use a null value for members that cannot be parsed.</param>
1213
/// <returns></returns>
13-
public static JsonSerializerOptions UseStringEnums(this JsonSerializerOptions options)
14+
public static JsonSerializerOptions UseStringEnums(this JsonSerializerOptions options, NoMemberFoundBehavior noMemberFoundBehavior = NoMemberFoundBehavior.ThrowException)
1415
{
15-
options.Converters.Add(new StringEnumJsonConverterFactory());
16+
options.Converters.Add(new StringEnumJsonConverterFactory(noMemberFoundBehavior));
1617

1718
return options;
1819
}

test/StrEnum.System.Text.Json.IntegrationTests/DeserializeTests.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Text.Json;
22
using FluentAssertions;
3+
using StrEnum.System.Text.Json.Converters;
34
using Xunit;
45

56
namespace StrEnum.System.Text.Json.IntegrationTests
@@ -30,7 +31,7 @@ public void Deserialize_GivenJsonWithEnumsValue_ShouldDeserializesItWithValidEnu
3031
}
3132

3233
[Fact]
33-
public void Deserialize_GivenJsonWithEnumsName_ShouldThrowAnException()
34+
public void Deserialize_GivenJsonWithEnumsName_AndDefaultNoMemberBehavior_ShouldThrowAnException()
3435
{
3536
var json = @"{""sport"":""TrailRunning""}";
3637

@@ -57,7 +58,7 @@ public void Deserialize_GivenJsonWithNull_ShouldDeserializesItWithNull()
5758
}
5859

5960
[Fact]
60-
public void Deserialize_GivenJsonWithInvalidValue_ShouldThrowAnException()
61+
public void Deserialize_GivenJsonWithInvalidValue_AndDefaultNoMemberBehavior_ShouldThrowAnException()
6162
{
6263
var json = @"{""sport"":""Quidditch""}";
6364

@@ -69,5 +70,18 @@ public void Deserialize_GivenJsonWithInvalidValue_ShouldThrowAnException()
6970
deserialize.Should().Throw<JsonException>()
7071
.WithMessage("Requested name or value 'Quidditch' was not found in the string enum 'Sport'.");
7172
}
73+
74+
[Fact]
75+
public void Deserialize_GivenJsonWithInvalidValue_AndReturnNullNoMemberBehavior_ShouldThrowAnException()
76+
{
77+
var json = @"{""sport"":""Quidditch""}";
78+
79+
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }
80+
.UseStringEnums(NoMemberFoundBehavior.ReturnNull);
81+
82+
var obj = JsonSerializer.Deserialize<DeserializedObject>(json, options);
83+
84+
obj.Should().BeEquivalentTo(new { Sport = (Sport?)null });
85+
}
7286
}
7387
}

0 commit comments

Comments
 (0)