Skip to content

Commit fa78a97

Browse files
committed
Add DateTimeConverterResolver
1 parent ab7f880 commit fa78a97

8 files changed

Lines changed: 153 additions & 6 deletions

File tree

build/Build.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using Nuke.Common.Utilities.Collections;
1414
using Serilog;
1515
using static Nuke.Common.EnvironmentInfo;
16-
using static Nuke.Common.IO.FileSystemTasks;
1716
using static Nuke.Common.IO.PathConstruction;
1817
using static Nuke.Common.Tools.DotNet.DotNetTasks;
1918

build/_build.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net8.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
<RootNamespace></RootNamespace>
77
<NoWarn>CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006</NoWarn>
88
<NukeRootDirectory>..</NukeRootDirectory>
@@ -12,7 +12,7 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="Nuke.Common" Version="8.1.2" />
15+
<PackageReference Include="Nuke.Common" Version="10.1.0" />
1616
</ItemGroup>
1717

1818
</Project>

src/Scarlet.System.Text.Json.DateTimeConverter.Tests/JsonDateTimeFormatConverterTests.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,79 @@ public void SerializeAndDeserialize_SourceGenerator_TestModel_ShouldMatchOrigina
114114
Assert.Equal(expectedJson, json);
115115
}
116116

117+
[Fact]
118+
public void SerializeAndDeserialize_SourceGenerator_TypeInfoResolver_TestModel_ShouldMatchOriginal()
119+
{
120+
// Arrange
121+
var sourceGenOptions = new JsonSerializerOptions
122+
{
123+
WriteIndented = true,
124+
TypeInfoResolver = new DateTimeConverterResolver(TestModelSourceGeneratorJsonSerializerContext.Default)
125+
};
126+
var originalModel = new TestModelSourceGeneratorAttributes
127+
{
128+
DateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
129+
NullableDateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
130+
DateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero),
131+
NullableDateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero)
132+
};
133+
const string expectedJson = """
134+
{
135+
"DateTimeProperty": "2023-10-01T12:00:00",
136+
"NullableDateTimeProperty": "2023-10-01T12:00:00",
137+
"DateTimeOffsetProperty": "2023-10-01T12:00:00.000Z",
138+
"NullableDateTimeOffsetProperty": "2023-10-01T12:00:00.000Z"
139+
}
140+
""";
141+
142+
// Act
143+
var json = JsonSerializer.Serialize(originalModel, sourceGenOptions);
144+
var deserializedModel = JsonSerializer.Deserialize<TestModelSourceGenerator>(json, sourceGenOptions);
145+
146+
// Assert
147+
Assert.NotNull(deserializedModel);
148+
Assert.Equal(originalModel.DateTimeProperty, deserializedModel.DateTimeProperty);
149+
Assert.Equal(originalModel.NullableDateTimeProperty, deserializedModel.NullableDateTimeProperty);
150+
Assert.Equal(originalModel.DateTimeOffsetProperty, deserializedModel.DateTimeOffsetProperty);
151+
Assert.Equal(originalModel.NullableDateTimeOffsetProperty, deserializedModel.NullableDateTimeOffsetProperty);
152+
Assert.Equal(expectedJson, json);
153+
}
154+
155+
[Fact]
156+
public void SerializeAndDeserialize_SourceGeneratorWithResolver_JsonSerializerContext_TestModel_ShouldMatchOriginal()
157+
{
158+
// Arrange
159+
var testModelType = typeof(TestModelSourceGeneratorAttributes);
160+
var context = new DateTimeConverterResolver(TestModelSourceGeneratorJsonSerializerContext.Default);
161+
var originalModel = new TestModelSourceGeneratorAttributes
162+
{
163+
DateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
164+
NullableDateTimeProperty = new DateTime(2023, 10, 1, 12, 0, 0, DateTimeKind.Utc),
165+
DateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero),
166+
NullableDateTimeOffsetProperty = new DateTimeOffset(2023, 10, 1, 12, 0, 0, TimeSpan.Zero)
167+
};
168+
const string expectedJson = """
169+
{
170+
"DateTimeProperty": "2023-10-01T12:00:00",
171+
"NullableDateTimeProperty": "2023-10-01T12:00:00",
172+
"DateTimeOffsetProperty": "2023-10-01T12:00:00.000Z",
173+
"NullableDateTimeOffsetProperty": "2023-10-01T12:00:00.000Z"
174+
}
175+
""";
176+
177+
// Act
178+
var json = JsonSerializer.Serialize(originalModel, testModelType, context);
179+
var deserializedModel = (TestModelSourceGeneratorAttributes?)JsonSerializer.Deserialize(json, testModelType, context);
180+
181+
// Assert
182+
Assert.NotNull(deserializedModel);
183+
Assert.Equal(originalModel.DateTimeProperty, deserializedModel.DateTimeProperty);
184+
Assert.Equal(originalModel.NullableDateTimeProperty, deserializedModel.NullableDateTimeProperty);
185+
Assert.Equal(originalModel.DateTimeOffsetProperty, deserializedModel.DateTimeOffsetProperty);
186+
Assert.Equal(originalModel.NullableDateTimeOffsetProperty, deserializedModel.NullableDateTimeOffsetProperty);
187+
Assert.Equal(expectedJson, json);
188+
}
189+
117190
[Fact]
118191
public void SerializeAndDeserialize_SourceGenerator_TestModel_WithNullValues_ShouldMatchOriginal()
119192
{
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Scarlet.System.Text.Json.DateTimeConverter.Tests.Model;
2+
3+
public class TestModelSourceGeneratorAttributes
4+
{
5+
[JsonDateTimeConverter("yyyy-MM-ddTHH:mm:ss")]
6+
public DateTime DateTimeProperty { get; set; }
7+
8+
[JsonDateTimeConverter("yyyy-MM-ddTHH:mm:ss")]
9+
public DateTime? NullableDateTimeProperty { get; set; }
10+
11+
[JsonDateTimeConverter("yyyy-MM-ddTHH:mm:ss.fffZ")]
12+
public DateTimeOffset DateTimeOffsetProperty { get; set; }
13+
14+
[JsonDateTimeConverter("yyyy-MM-ddTHH:mm:ss.fffZ")]
15+
public DateTimeOffset? NullableDateTimeOffsetProperty { get; set; }
16+
}

src/Scarlet.System.Text.Json.DateTimeConverter.Tests/Model/TestModelSourceGeneratorJsonSerializerContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
namespace Scarlet.System.Text.Json.DateTimeConverter.Tests.Model;
44

55
[JsonSerializable(typeof(TestModelSourceGenerator))]
6+
[JsonSerializable(typeof(TestModelSourceGeneratorAttributes))]
67
[JsonSourceGenerationOptions(WriteIndented = true)]
78
public sealed partial class TestModelSourceGeneratorJsonSerializerContext : JsonSerializerContext;

src/Scarlet.System.Text.Json.DateTimeConverter.Tests/Scarlet.System.Text.Json.DateTimeConverter.Tests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net6.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<LangVersion>latest</LangVersion>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#if NET9_0_OR_GREATER
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
4+
using System.Text.Json.Serialization.Metadata;
5+
6+
namespace Scarlet.System.Text.Json.DateTimeConverter;
7+
8+
public class DateTimeConverterResolver : JsonSerializerContext, IJsonTypeInfoResolver
9+
{
10+
private readonly IJsonTypeInfoResolver? _source;
11+
12+
public DateTimeConverterResolver(IJsonTypeInfoResolver source) : base(null)
13+
{
14+
_source = source;
15+
}
16+
17+
public DateTimeConverterResolver() : base(null)
18+
{
19+
}
20+
21+
public DateTimeConverterResolver(JsonSerializerOptions options) : base(options)
22+
{
23+
}
24+
25+
public JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options)
26+
{
27+
JsonTypeInfo? jsonTypeInfo = _source?.GetTypeInfo(type, options);
28+
29+
if (jsonTypeInfo is null)
30+
{
31+
return null;
32+
}
33+
34+
foreach (var jsonPropertyInfo in jsonTypeInfo.Properties)
35+
{
36+
if (jsonPropertyInfo.AttributeProvider?.GetCustomAttributes(typeof(JsonDateTimeConverterAttribute), inherit: false) is [JsonDateTimeConverterAttribute attr, ..])
37+
{
38+
jsonPropertyInfo.CustomConverter = attr.CreateConverter(jsonPropertyInfo.PropertyType);
39+
}
40+
}
41+
42+
return jsonTypeInfo;
43+
}
44+
45+
public override JsonTypeInfo? GetTypeInfo(Type type)
46+
{
47+
// We are wrapping DateTimeConverterResolver(SourceGeneratorXXX.Default) so it makes sense to forward the Options from SourceGeneratorXXX
48+
if (_source is JsonSerializerContext jsonSerializerContext)
49+
{
50+
return GetTypeInfo(type, jsonSerializerContext.Options);
51+
}
52+
53+
return GetTypeInfo(type, Options);
54+
}
55+
56+
protected override JsonSerializerOptions? GeneratedSerializerOptions => null;
57+
}
58+
#endif

src/Scarlet.System.Text.Json.DateTimeConverter/Scarlet.System.Text.Json.DateTimeConverter.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
4+
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<LangVersion>latest</LangVersion>

0 commit comments

Comments
 (0)