Skip to content

Commit c2f2b5c

Browse files
authored
Merge pull request #1975 from riganti/fix-enum-custom-json-converter
Fix custom JSON converter on enum (or other type)
2 parents a8947e5 + 2d46a66 commit c2f2b5c

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

src/Framework/Framework/Configuration/DefaultSerializerSettingsProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ private JsonSerializerOptions CreateSettings()
3434
return new JsonSerializerOptions()
3535
{
3636
Converters = {
37+
new PreferTheJsonConverterAttribute(),
3738
new DotvvmDateTimeConverter(),
3839
new DotvvmObjectConverter(),
3940
new DotvvmEnumConverter(),
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Reflection;
3+
using System.Text.Json;
4+
using System.Text.Json.Serialization;
5+
using DotVVM.Framework.Utils;
6+
using FastExpressionCompiler;
7+
8+
namespace DotVVM.Framework.ViewModel.Serialization
9+
{
10+
public sealed class PreferTheJsonConverterAttribute : JsonConverterFactory
11+
{
12+
public override bool CanConvert(Type typeToConvert)
13+
{
14+
if (!typeToConvert.IsDefined(typeof(JsonConverterAttribute), inherit: false))
15+
return false;
16+
var attr = typeToConvert.GetCustomAttribute<JsonConverterAttribute>(inherit: false)!;
17+
return attr.ConverterType is {} || attr.CreateConverter(typeToConvert) is {};
18+
}
19+
20+
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
21+
{
22+
var attr = typeToConvert.GetCustomAttribute<JsonConverterAttribute>(inherit: false)!;
23+
if (attr.CreateConverter(typeToConvert) is {} converter)
24+
return converter;
25+
if (attr.ConverterType is null)
26+
throw new Exception($"Type {typeToConvert.ToCode()} has a [JsonConverter] attribute, but its CreateConverter returns null sometimes?");
27+
return (JsonConverter)Activator.CreateInstance(attr.ConverterType)!;
28+
}
29+
}
30+
}
31+

src/Tests/ViewModel/SerializerTests.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,14 @@ public void Serializer_CanDisableDotvvmSerializer()
14371437
Assert.IsTrue(obj.ItsSerializedAnyway);
14381438
}
14391439

1440+
[TestMethod]
1441+
public void Serializer_SupportCustomEnumConverter()
1442+
{
1443+
var (obj, json) = SerializeAndDeserialize<Tuple<TestEnumWithCustomConverter>>(new(TestEnumWithCustomConverter.Case5));
1444+
1445+
Assert.AreEqual(TestEnumWithCustomConverter.Case5, obj.Item1);
1446+
Assert.AreEqual("5esaC", (string)json["Item1"]);
1447+
}
14401448

14411449
[TestMethod]
14421450
public void Serializer_CanUseDefaultPolymorphismSupport_1()
@@ -1858,6 +1866,23 @@ public override void Write(Utf8JsonWriter writer, TestViewModelWithCustomConvert
18581866
}
18591867
}
18601868

1869+
[JsonConverter(typeof(TestEnumCustomConverter))]
1870+
public enum TestEnumWithCustomConverter { Case1, Case2, Case3, Case4, Case5, Case6, Case7 }
1871+
1872+
public class TestEnumCustomConverter : JsonConverter<TestEnumWithCustomConverter>
1873+
{
1874+
public override TestEnumWithCustomConverter Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1875+
{
1876+
var str = reader.GetString();
1877+
return (TestEnumWithCustomConverter)Enum.Parse(typeof(TestEnumWithCustomConverter), new string(str.Reverse().ToArray()));
1878+
}
1879+
1880+
public override void Write(Utf8JsonWriter writer, TestEnumWithCustomConverter value, JsonSerializerOptions options)
1881+
{
1882+
writer.WriteStringValue(new string(value.ToString().Reverse().ToArray()));
1883+
}
1884+
}
1885+
18611886
class DynamicDispatchVMContainer<TStatic>
18621887
{
18631888
[Bind(AllowDynamicDispatch = true)]

0 commit comments

Comments
 (0)