Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

hotfix/down cast fix #138

Merged
merged 6 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

## [1.1.1] - 2023-10-23

### Changed

- Fixed a bug where deserialization of downcast type fields would be ignored.

## [1.1.0] - 2023-10-23

### Added
Expand Down
41 changes: 40 additions & 1 deletion Microsoft.Kiota.Serialization.Json.Tests/JsonParseNodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ public class JsonParseNodeTests
" \"birthDay\": \"2017-09-04\",\r\n" +
" \"id\": \"48d31887-5fad-4d73-a9f5-3c356e68a038\"\r\n" +
"}";
private const string TestStudentJson = "{\r\n" +
" \"@odata.context\": \"https://graph.microsoft.com/v1.0/$metadata#users/$entity\",\r\n" +
" \"@odata.type\": \"microsoft.graph.student\",\r\n" +
" \"@odata.id\": \"https://graph.microsoft.com/v2/dcd219dd-bc68-4b9b-bf0b-4a33a796be35/directoryObjects/48d31887-5fad-4d73-a9f5-3c356e68a038/Microsoft.DirectoryServices.User\",\r\n" +
" \"businessPhones\": [\r\n" +
" \"+1 412 555 0109\"\r\n" +
" ],\r\n" +
" \"displayName\": \"Megan Bowen\",\r\n" +
" \"numbers\":\"one,two,thirtytwo\"," +
" \"testNamingEnum\":\"Item2:SubItem1\"," +
" \"givenName\": \"Megan\",\r\n" +
" \"accountEnabled\": true,\r\n" +
" \"createdDateTime\": \"2017 -07-29T03:07:25Z\",\r\n" +
" \"jobTitle\": \"Auditor\",\r\n" +
" \"mail\": \"[email protected]\",\r\n" +
" \"mobilePhone\": null,\r\n" +
" \"officeLocation\": null,\r\n" +
" \"preferredLanguage\": \"en-US\",\r\n" +
" \"surname\": \"Bowen\",\r\n" +
" \"workDuration\": \"PT1H\",\r\n" +
" \"startWorkTime\": \"08:00:00.0000000\",\r\n" +
" \"endWorkTime\": \"17:00:00.0000000\",\r\n" +
" \"userPrincipalName\": \"[email protected]\",\r\n" +
" \"birthDay\": \"2017-09-04\",\r\n" +
" \"enrolmentDate\": \"2017-09-04\",\r\n" +
" \"id\": \"48d31887-5fad-4d73-a9f5-3c356e68a038\"\r\n" +
"}";

private static readonly string TestUserCollectionString = $"[{TestUserJson}]";

Expand All @@ -44,7 +71,7 @@ public void GetsEntityValueFromJson()
using var jsonDocument = JsonDocument.Parse(TestUserJson);
var jsonParseNode = new JsonParseNode(jsonDocument.RootElement);
// Act
var testEntity = jsonParseNode.GetObjectValue<TestEntity>(x => new TestEntity());
var testEntity = jsonParseNode.GetObjectValue(TestEntity.CreateFromDiscriminator);
// Assert
Assert.NotNull(testEntity);
Assert.Null(testEntity.OfficeLocation);
Expand All @@ -60,6 +87,18 @@ public void GetsEntityValueFromJson()
Assert.Equal(new Time(17, 0, 0).ToString(), testEntity.EndWorkTime.ToString());// Parses time values
Assert.Equal(new Date(2017,9,4).ToString(), testEntity.BirthDay.ToString());// Parses date values
}
[Fact]
public void GetsFieldFromDerivedType()
{
// Arrange
using var jsonDocument = JsonDocument.Parse(TestStudentJson);
var jsonParseNode = new JsonParseNode(jsonDocument.RootElement);
// Act
var testEntity = jsonParseNode.GetObjectValue(TestEntity.CreateFromDiscriminator) as DerivedTestEntity;
// Assert
Assert.NotNull(testEntity);
Assert.NotNull(testEntity.EnrolmentDate);
}

[Fact]
public void GetCollectionOfObjectValuesFromJson()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Serialization;

namespace Microsoft.Kiota.Serialization.Json.Tests.Mocks
{
public class DerivedTestEntity : TestEntity
{
/// <summary>
/// Date enrolled in primary school
/// </summary>
public Date? EnrolmentDate { get; set; }
public override IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
var parentDeserializers = base.GetFieldDeserializers();
parentDeserializers.Add("enrolmentDate", n => { EnrolmentDate = n.GetDateValue(); });
return parentDeserializers;
}
public override void Serialize(ISerializationWriter writer)
{
base.Serialize(writer);
writer.WriteDateValue("enrolmentDate", EnrolmentDate.Value);
}
}
}
13 changes: 10 additions & 3 deletions Microsoft.Kiota.Serialization.Json.Tests/Mocks/TestEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public TestEntity()
/// <summary>
/// The deserialization information for the current model
/// </summary>
public IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>> {
{"id", n => { Id = n.GetStringValue(); } },
Expand All @@ -55,7 +55,7 @@ public IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
/// Serializes information the current object
/// <param name="writer">Serialization writer to use to serialize this model</param>
/// </summary>
public void Serialize(ISerializationWriter writer)
public virtual void Serialize(ISerializationWriter writer)
{
_ = writer ?? throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("id", Id);
Expand All @@ -70,7 +70,14 @@ public void Serialize(ISerializationWriter writer)
writer.WriteAdditionalData(AdditionalData);
}
public static TestEntity CreateFromDiscriminator(IParseNode parseNode) {
return new TestEntity();
var discriminatorValue = parseNode.GetChildNode("@odata.type")?.GetStringValue();
return discriminatorValue switch
{
"microsoft.graph.user" => new TestEntity(),
"microsoft.graph.group" => new TestEntity(),
"microsoft.graph.student" => new DerivedTestEntity(),
_ => new TestEntity(),
};
}
}
}
8 changes: 1 addition & 7 deletions src/JsonParseNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,7 @@ public T GetObjectValue<T>(ParsableFactory<T> factory) where T : IParsable
OnAfterAssignFieldValues?.Invoke(item);
return item;
}
#if NET5_0_OR_GREATER
private void AssignFieldValues<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(T item) where T : IParsable
#else
private void AssignFieldValues<T>(T item) where T : IParsable
#endif
{
if(_jsonNode.ValueKind != JsonValueKind.Object) return;
IDictionary<string, object>? itemAdditionalData = null;
Expand All @@ -325,9 +321,7 @@ private void AssignFieldValues<T>(T item) where T : IParsable
holder.AdditionalData ??= new Dictionary<string, object>();
itemAdditionalData = holder.AdditionalData;
}
//When targeting maccatalyst, new keyword for hiding an existing member is not being respected, returning only id and odata type
//the below line fixes the issue
var fieldDeserializers = typeof(T).GetMethod("GetFieldDeserializers")?.Invoke(item, null) is IDictionary<string, Action<IParseNode>> result ? result : item.GetFieldDeserializers();
var fieldDeserializers = item.GetFieldDeserializers();

foreach(var fieldValue in _jsonNode.EnumerateObject())
{
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.Kiota.Serialization.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageProjectUrl>https://aka.ms/kiota/docs</PackageProjectUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<Deterministic>true</Deterministic>
<VersionPrefix>1.1.0</VersionPrefix>
<VersionPrefix>1.1.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down