Skip to content

Comments

Add JsonConverter classes for Date and Time to support System.Text.Json deserialization#641

Open
Copilot wants to merge 5 commits intomainfrom
copilot/fix-json-deserialization-date-time
Open

Add JsonConverter classes for Date and Time to support System.Text.Json deserialization#641
Copilot wants to merge 5 commits intomainfrom
copilot/fix-json-deserialization-date-time

Conversation

Copy link
Contributor

Copilot AI commented Feb 4, 2026

Fix Date and Time deserialization with System.Text.Json ✅

Summary

Successfully fixed the deserialization issue with Date and Time types when using System.Text.Json.JsonSerializer by providing JsonConverter classes in the serialization package, keeping the abstractions project free of serialization dependencies.

Approach

Based on maintainer feedback, the solution uses JsonConverter classes instead of JsonConstructor attributes to maintain the design principle that abstractions should NOT be tied to any serialization format.

Changes Made:

Serialization Package (Microsoft.Kiota.Serialization.Json)

  1. Created DateJsonConverter.cs: JsonConverter that serializes Date to/from "yyyy-MM-dd" string format
  2. Created TimeJsonConverter.cs: JsonConverter that serializes Time to/from "HH:mm:ss" string format
  3. Updated KiotaJsonSerializationContext.cs: Added DefaultOptionsWithConverters static property that provides pre-configured JsonSerializerOptions with converters registered
  4. Updated README.md: Added documentation with usage examples for the converters

Tests

  1. Created DateJsonConverterTests.cs: 8 comprehensive tests covering serialization, deserialization, round-trip, null handling, and error cases
  2. Created TimeJsonConverterTests.cs: 8 comprehensive tests covering serialization, deserialization, round-trip, null handling, and error cases
  3. Cleaned up TimeTests.cs: Removed JSON-specific tests from abstractions, keeping only type-specific tests

Usage Examples:

Option 1: Using DefaultOptionsWithConverters

using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Serialization.Json;
using System.Text.Json;

var date = new Date(2025, 10, 24);
var json = JsonSerializer.Serialize(date, KiotaJsonSerializationContext.DefaultOptionsWithConverters);
// Output: "2025-10-24"

var deserialized = JsonSerializer.Deserialize<Date>(json, KiotaJsonSerializationContext.DefaultOptionsWithConverters);
// deserialized.Year == 2025, deserialized.Month == 10, deserialized.Day == 24

Option 2: Manually Registering Converters

var options = new JsonSerializerOptions();
options.Converters.Add(new DateJsonConverter());
options.Converters.Add(new TimeJsonConverter());

var time = new Time(10, 18, 54);
var json = JsonSerializer.Serialize(time, options);
// Output: "10:18:54"

Test Results:

  • ✅ All 16 converter tests pass (8 for Date, 8 for Time)
  • ✅ All abstractions tests still pass
  • ✅ Manual verification confirms deserialized objects contain correct values instead of default values
  • ✅ Code review: Completed
  • ✅ Security scan: No vulnerabilities found
  • ✅ Code formatting: Passes dotnet format verification

Design Principles:

This approach maintains the key design principle that the abstractions project should be format-agnostic. All serialization-specific code is contained within the Microsoft.Kiota.Serialization.Json package, allowing users who need System.Text.Json support to opt-in via the converters while keeping the core abstractions clean.

Security Summary:

No security vulnerabilities were discovered or introduced by this change.

Original prompt

This section details on the original issue you should resolve

<issue_title>System.Text.Json.JsonSerializer cannot deserialize Date and Time types using default converters</issue_title>
<issue_description>Hello!

The default JSON converters in System.Text.Json do not work with the Date or Time types. These types are serialized as objects containing the read-only properties. Those properties are not set when deserializing, so they get the default values. Same issue applies with Newtonsoft.Json.

This is a problem when using third-party libraries that can't use KiotaJsonSerializer or the extension methods. My specific use case is using Temporal, which serializes values returned from activities and deserializes them later. I had an activity that returned a Kiota-generated model with a date, but the date later deserialized to 0001-01-01. This is easy to fix by creating a type that uses DateOnly or registering a new JsonConverter, but the bug confused me for a while.

This was briefly mentioned in #282 which was closed due to no response. That issue also mentions serializing enums, which I haven't tried.

Demo: (.NET 9.0.10 using Microsoft.Kiota.Abstractions v1.20.1)

var date = new Date(DateTime.Now);

var dateSerialized = JsonSerializer.Serialize(date);
// {
//    "DateTime": "2025-10-24T10:18:54.5003283-05:00",
//    "Year": 2025,
//    "Month": 10,
//    "Day": 24
// }

var dateDeserialized = JsonSerializer.Deserialize<Date>(dateSerialized);
// {
//    DateTime = 1/1/0001 12:00:00 AM
//    Year = 1
//    Month = 1
//    Day = 1
// }

var time = new Time(DateTime.Now);

var timeSerialized = JsonSerializer.Serialize(time);
// {
//    "DateTime": "2025-10-24T10:18:54.5090402-05:00",
//    "Hour": 10,
//    "Minute": 18,
//    "Second": 54
// }

var timeDeserialized = JsonSerializer.Deserialize<Time>(timeSerialized);
// {
//    DateTime = 1/1/0001 12:00:00 AM
//    Hour = 1
//    Minute = 1
//    Second = 1
// }

This could be fixed a couple different ways:

  1. Change the DateTime property from { get; } to { get; init; }. This also fixes deserialization with Newtonsoft.Json. I can't think of any downside.
  2. Add [JsonConstructor] to one of the constructors so the JSON properties are used in the constructor arguments.
  3. Provide JsonConverters that mimic KiotaJsonSerializer. This would also fix serialization so they are written as strings instead of objects, but that might technically be a breaking change.</issue_description>

<agent_instructions>Please add JsonConstructor attribute to the best choice of constructor for these classes and write tests to validate the functionality.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@gavinbarron Thanks for raising this @n0spaces

init is a c#9 feature, as we produce code to be compatible with netstandard2.0 this restricts the language features that we can use. At present we do use a few C#8.0 features that can be used without additional types and remain compatible with netstandard2.0. So that's out at the moment.

the [JsonConstructor] option is probably the best way forward here as it represents the lowest risk.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…ation

Co-authored-by: gavinbarron <7122716+gavinbarron@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix deserialization issue for Date and Time types in JSON Add JsonConstructor attributes to Date and Time for System.Text.Json deserialization Feb 4, 2026
Copilot AI requested a review from gavinbarron February 4, 2026 00:38
@gavinbarron gavinbarron marked this pull request as ready for review February 6, 2026 03:07
@gavinbarron gavinbarron requested a review from a team as a code owner February 6, 2026 03:07
@gavinbarron
Copy link
Contributor

@copilot please run dotnet format

Co-authored-by: gavinbarron <7122716+gavinbarron@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot please run dotnet format

Done! Applied formatting in commit 09fab74.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 6, 2026

Copy link
Member

@baywet baywet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the key design principles of abstractions is to NOT be tied to any serialization format.
These changes completely disregard that aspect.
The OP suggested two other approaches: JsonConverter, or a setter/init.
I'm in favour of the converter approach.

@github-project-automation github-project-automation bot moved this to In Progress 🚧 in Kiota Feb 6, 2026
@gavinbarron
Copy link
Contributor

Thanks @baywet I was unaware of that design goal. and with that in mind yes, the converter is the best approach here.

@gavinbarron
Copy link
Contributor

@copilot Let's change direction and instead of using a [JsonConstructor] let's provide a JsonConverter for each of these types

Co-authored-by: gavinbarron <7122716+gavinbarron@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot Let's change direction and instead of using a [JsonConstructor] let's provide a JsonConverter for each of these types

Done! Changed to use JsonConverter approach in commit aa05ced. The converters are now in the serialization/json project, keeping abstractions free of serialization dependencies. Users can access them via KiotaJsonSerializationContext.DefaultOptionsWithConverters or manually register DateJsonConverter and TimeJsonConverter with their JsonSerializerOptions.

Copilot AI changed the title Add JsonConstructor attributes to Date and Time for System.Text.Json deserialization Add JsonConverter classes for Date and Time to support System.Text.Json deserialization Feb 6, 2026
@@ -34,4 +35,24 @@ namespace Microsoft.Kiota.Serialization.Json;
[JsonSerializable(typeof(Date?))]
[JsonSerializable(typeof(Time))]
[JsonSerializable(typeof(Time?))]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious: should these attributes be updated to point to the converters as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress 🚧

Development

Successfully merging this pull request may close these issues.

System.Text.Json.JsonSerializer cannot deserialize Date and Time types using default converters

3 participants