Skip to content

Commit

Permalink
Merge pull request #307 from greg-ww/main
Browse files Browse the repository at this point in the history
Add support to JsonSerializationWriter.WriteNonParsableObjectValue for anonymous objects.
  • Loading branch information
baywet authored Jul 31, 2024
2 parents 1eca71b + 799c405 commit 148396a
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.9.12] - 2024-07-30

- Fix non IParasable object serialization.
- Add basic support for serializing dictionary values in AdditionalData.

## [1.9.11] - 2024-07-22

- Obsoletes custom decompression handler in favor of native client capabilities.
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<!-- Common default project properties for ALL projects-->
<PropertyGroup>
<VersionPrefix>1.9.11</VersionPrefix>
<VersionPrefix>1.9.12</VersionPrefix>
<VersionSuffix></VersionSuffix>
<!-- This is overidden in test projects by setting to true-->
<IsTestProject>false</IsTestProject>
Expand Down
38 changes: 34 additions & 4 deletions src/serialization/json/JsonSerializationWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// ------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
Expand Down Expand Up @@ -344,7 +345,7 @@ public void WriteCollectionOfObjectValues<T>(string? key, IEnumerable<T>? values
/// <param name="key">The key to be used for the written value. May be null.</param>
/// <param name="values">The enum values to be written.</param>
#if NET5_0_OR_GREATER
public void WriteCollectionOfEnumValues<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]T>(string? key, IEnumerable<T?>? values) where T : struct, Enum
public void WriteCollectionOfEnumValues<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(string? key, IEnumerable<T?>? values) where T : struct, Enum
#else
public void WriteCollectionOfEnumValues<T>(string? key, IEnumerable<T?>? values) where T : struct, Enum
#endif
Expand All @@ -360,6 +361,32 @@ public void WriteCollectionOfEnumValues<T>(string? key, IEnumerable<T?>? values)
}
}
/// <summary>
/// Writes the specified dictionary to the stream with an optional given key.
/// </summary>
/// <param name="key">The key to be used for the written value. May be null.</param>
/// <param name="values">The dictionary of values to be written.</param>
#if NET5_0_OR_GREATER
private void WriteDictionaryValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] T>(string? key, T values) where T : IDictionary
#else
private void WriteDictionaryValue<T>(string? key, T values) where T : IDictionary
#endif
{
if(values != null)
{
if(!string.IsNullOrEmpty(key))
writer.WritePropertyName(key!);

writer.WriteStartObject();
foreach(DictionaryEntry entry in values)
{
if(entry.Key is not string keyStr)
throw new InvalidOperationException($"Error serializing dictionary value with key {key}, only string keyed dictionaries are supported.");
WriteAnyValue(keyStr, entry.Value);
}
writer.WriteEndObject();
}
}
/// <summary>
/// Writes the specified byte array as a base64 string to the stream with an optional given key.
/// </summary>
/// <param name="key">The key to be used for the written value. May be null.</param>
Expand Down Expand Up @@ -433,7 +460,7 @@ public void WriteAdditionalData(IDictionary<string, object> value)
}

#if NET5_0_OR_GREATER
private void WriteNonParsableObjectValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string? key,T value)
private void WriteNonParsableObjectValue<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(string? key, T value)
#else
private void WriteNonParsableObjectValue<T>(string? key, T value)
#endif
Expand All @@ -444,7 +471,7 @@ private void WriteNonParsableObjectValue<T>(string? key, T value)
if(value == null)
writer.WriteNullValue();
else
foreach(var oProp in typeof(T).GetProperties())
foreach(var oProp in value.GetType().GetProperties())
WriteAnyValue(oProp.Name, oProp.GetValue(value));
writer.WriteEndObject();
}
Expand Down Expand Up @@ -512,14 +539,17 @@ private void WriteAnyValue<T>(string? key, T value)
writer.WritePropertyName(key!);
jsonElement.WriteTo(writer);
break;
case IDictionary dictionary:
WriteDictionaryValue(key, dictionary);
break;
case object o:
WriteNonParsableObjectValue(key, o);
break;
case null:
WriteNullValue(key);
break;
default:
throw new InvalidOperationException($"error serialization additional data value with key {key}, unknown type {value?.GetType()}");
throw new InvalidOperationException($"Error serializing additional data value with key {key}, unknown type {value?.GetType()}");
}
}

Expand Down
27 changes: 26 additions & 1 deletion tests/serialization/json/JsonSerializationWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ public void WritesSampleObjectValue()
{"businessPhones", new List<string>() {"+1 412 555 0109"}}, // write collection of primitives value
{"endDateTime", new DateTime(2023,03,14,0,0,0,DateTimeKind.Utc) }, // ensure the DateTime doesn't crash
{"manager", new TestEntity{Id = "48d31887-5fad-4d73-a9f5-3c356e68a038"}}, // write nested object value
{"anonymousObject", new {Value1 = true, Value2 = "", Value3 = new List<string>{ "Value3.1", "Value3.2"}}}, // write nested object value
{"dictionaryString", new Dictionary<string, string>{{"91bbe8e2-09b2-482b-a90e-00f8d7e81636", "b7992f48-a51b-41a1-ace5-4cebb7f111d0"}, { "ed64c116-2776-4012-94d1-a348b9d241bd", "55e1b4d0-2959-4c71-89b5-385ba5338a1c" }, }}, // write a Dictionary
{"dictionaryTestEntity", new Dictionary<string, TestEntity>{{ "dd476fc9-7e97-4a4e-8d40-6c3de7432eb3", new TestEntity { Id = "dd476fc9-7e97-4a4e-8d40-6c3de7432eb3" } }, { "ffa5c351-7cf5-43df-9b55-e12455cf6eb2", new TestEntity { Id = "ffa5c351-7cf5-43df-9b55-e12455cf6eb2" } }, }}, // write a Dictionary
}
};

using var jsonSerializerWriter = new JsonSerializationWriter();
// Act
jsonSerializerWriter.WriteObjectValue(string.Empty, testEntity);
Expand All @@ -65,7 +69,10 @@ public void WritesSampleObjectValue()
"\"weightInKgs\":51.80," +
"\"businessPhones\":[\"\\u002B1 412 555 0109\"]," +
"\"endDateTime\":\"2023-03-14T00:00:00+00:00\"," +
"\"manager\":{\"id\":\"48d31887-5fad-4d73-a9f5-3c356e68a038\"}" +
"\"manager\":{\"id\":\"48d31887-5fad-4d73-a9f5-3c356e68a038\"}," +
"\"anonymousObject\":{\"Value1\":true,\"Value2\":\"\",\"Value3\":[\"Value3.1\",\"Value3.2\"]}," +
"\"dictionaryString\":{\"91bbe8e2-09b2-482b-a90e-00f8d7e81636\":\"b7992f48-a51b-41a1-ace5-4cebb7f111d0\",\"ed64c116-2776-4012-94d1-a348b9d241bd\":\"55e1b4d0-2959-4c71-89b5-385ba5338a1c\"}," +
"\"dictionaryTestEntity\":{\"dd476fc9-7e97-4a4e-8d40-6c3de7432eb3\":{\"id\":\"dd476fc9-7e97-4a4e-8d40-6c3de7432eb3\"},\"ffa5c351-7cf5-43df-9b55-e12455cf6eb2\":{\"id\":\"ffa5c351-7cf5-43df-9b55-e12455cf6eb2\"}}" +
"}";
Assert.Equal(expectedString, serializedJsonString);
}
Expand Down Expand Up @@ -161,6 +168,24 @@ public void WritesSampleCollectionOfObjectValues()
Assert.Equal(expectedString, serializedJsonString);
}

[Fact]
public void DoesntWriteUnsupportedTypes_NonStringKeyedDictionary()
{
// Arrange
var testEntity = new TestEntity()
{
AdditionalData = new Dictionary<string, object>
{
{"nonStringKeyedDictionary", new Dictionary<int, string>{{ 1, "one" }, { 2, "two" }}}
}
};

using var jsonSerializerWriter = new JsonSerializationWriter();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() => jsonSerializerWriter.WriteObjectValue(string.Empty, testEntity));
Assert.Equal("Error serializing dictionary value with key nonStringKeyedDictionary, only string keyed dictionaries are supported.", exception.Message);
}

[Fact]
public void WritesEnumValuesAsCamelCasedIfNotEscaped()
{
Expand Down

0 comments on commit 148396a

Please sign in to comment.