Skip to content

Commit

Permalink
Merge pull request #7 from chronoxor/master
Browse files Browse the repository at this point in the history
Serialize issue of Nullable enums/strcuts list with custom JsonFormatter #6
  • Loading branch information
zcsizmadia authored Jul 28, 2022
2 parents 2e1a270 + badc4a1 commit 1ba59c7
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 4 deletions.
25 changes: 21 additions & 4 deletions src/Utf8Json/Resolvers/AttributeFormatterResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Reflection;
using System.Collections.Generic;
using System.Text;
using Utf8Json.Formatters;
using Utf8Json.Internal;

namespace Utf8Json.Resolvers
Expand Down Expand Up @@ -29,10 +30,16 @@ static class FormatterCache<T>

static FormatterCache()
{
var ti = typeof(T).GetTypeInfo();
var genericTypeInfo = ti.GetTypeInfo();
var isNullable = genericTypeInfo.IsNullable();
var isStruct = genericTypeInfo.IsValueType && !genericTypeInfo.IsEnum;
var elementType = isNullable ? ti.GenericTypeArguments[0] : typeof(T);

#if (UNITY_METRO || UNITY_WSA) && !NETFX_CORE
var attr = (JsonFormatterAttribute)typeof(T).GetCustomAttributes(typeof(JsonFormatterAttribute), true).FirstOrDefault();
var attr = (JsonFormatterAttribute)elementType.GetCustomAttributes(typeof(JsonFormatterAttribute), true).FirstOrDefault();
#else
var attr = typeof(T).GetTypeInfo().GetCustomAttribute<JsonFormatterAttribute>();
var attr = elementType.GetTypeInfo().GetCustomAttribute<JsonFormatterAttribute>();
#endif
if (attr == null)
{
Expand All @@ -41,14 +48,24 @@ static FormatterCache()

try
{
object fmt;
if (attr.FormatterType.IsGenericType && !attr.FormatterType.GetTypeInfo().IsConstructedGenericType())
{
var t = attr.FormatterType.MakeGenericType(typeof(T)); // use T self
formatter = (IJsonFormatter<T>)Activator.CreateInstance(t, attr.Arguments);
fmt = Activator.CreateInstance(t, attr.Arguments);
}
else
{
fmt = Activator.CreateInstance(attr.FormatterType, attr.Arguments);
}

if (isNullable && isStruct)
{
formatter = (IJsonFormatter<T>)Activator.CreateInstance(typeof(StaticNullableFormatter<>).MakeGenericType(elementType), fmt);
}
else
{
formatter = (IJsonFormatter<T>)Activator.CreateInstance(attr.FormatterType, attr.Arguments);
formatter = (IJsonFormatter<T>)fmt;
}
}
catch (Exception ex)
Expand Down
113 changes: 113 additions & 0 deletions tests/Utf8Json.Tests/NullableFormatterTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#nullable enable

using System;
using System.Collections.Generic;
using Utf8Json.Resolvers;
using Xunit;

namespace Utf8Json.Tests
{
public class NullableFormatterTest
{
public class MyContainer
{
public List<int> field1 = new List<int>();
public List<int?> field2 = new List<int?>();
public List<string> field3 = new List<string>();
public List<string?> field4 = new List<string?>();
public List<DateTime> field5 = new List<DateTime>();
public List<DateTime?> field6 = new List<DateTime?>();
public List<MyClass> field7 = new List<MyClass>();
public List<MyClass?> field8 = new List<MyClass?>();
public List<MyStruct> field9 = new List<MyStruct>();
public List<MyStruct?> field10 = new List<MyStruct?>();
public List<MyEnum> field11 = new List<MyEnum>();
public List<MyEnum?> field12 = new List<MyEnum?>();
}

[JsonFormatter(typeof(MyClassConverter))]
public class MyClass
{
public int Value;

public MyClass(int value) { Value = value; }
}

public class MyClassConverter : IJsonFormatter<MyClass>
{
public void Serialize(ref JsonWriter writer, MyClass value, IJsonFormatterResolver jsonFormatterResolver)
{
if (value == null)
writer.WriteNull();
else
writer.WriteInt32(value.Value);
}

public MyClass Deserialize(ref JsonReader reader, IJsonFormatterResolver jsonFormatterResolver)
{
return new MyClass(reader.ReadInt32());
}
}

[JsonFormatter(typeof(MyStructConverter))]
public struct MyStruct
{
public int Value;

public MyStruct(int value) { Value = value; }
}

public class MyStructConverter : IJsonFormatter<MyStruct>
{
public void Serialize(ref JsonWriter writer, MyStruct value, IJsonFormatterResolver jsonFormatterResolver)
{
writer.WriteInt32(value.Value);
}

public MyStruct Deserialize(ref JsonReader reader, IJsonFormatterResolver jsonFormatterResolver)
{
return new MyStruct(reader.ReadInt32());
}
}

public enum MyEnum
{
Spring,
Summer,
Autumn,
Winter
}

[Fact]
public void Foo()
{
MyContainer container = new MyContainer();
container.field1.Add(1);
container.field1.Add(2);
container.field2.Add(10);
container.field2.Add(null);
container.field3.Add("100");
container.field3.Add("200");
container.field4.Add("1000");
container.field4.Add(null);
container.field5.Add(DateTime.UnixEpoch);
container.field5.Add(DateTime.UnixEpoch);
container.field6.Add(DateTime.UnixEpoch);
container.field6.Add(null);
container.field7.Add(new MyClass(1));
container.field7.Add(new MyClass(2));
container.field8.Add(new MyClass(10));
container.field8.Add(null);
container.field9.Add(new MyStruct(100));
container.field9.Add(new MyStruct(200));
container.field10.Add(new MyStruct(1000));
container.field10.Add(null);
container.field11.Add(MyEnum.Winter);
container.field11.Add(MyEnum.Spring);
container.field12.Add(MyEnum.Summer);
container.field12.Add(null);

JsonSerializer.NonGeneric.ToJsonString(container).Is("{\"field1\":[1,2],\"field2\":[10,null],\"field3\":[\"100\",\"200\"],\"field4\":[\"1000\",null],\"field5\":[\"1970-01-01T00:00:00Z\",\"1970-01-01T00:00:00Z\"],\"field6\":[\"1970-01-01T00:00:00Z\",null],\"field7\":[1,2],\"field8\":[10,null],\"field9\":[100,200],\"field10\":[1000,null],\"field11\":[\"Winter\",\"Spring\"],\"field12\":[\"Summer\",null]}");
}
}
}

0 comments on commit 1ba59c7

Please sign in to comment.