Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override T FromStream<T>(Stream stream)
public override Stream ToStream<T>(T input)
{
MemoryStream streamPayload = new MemoryStream();
this.systemTextJsonSerializer.Serialize(streamPayload, input, input.GetType(), default);
this.systemTextJsonSerializer.Serialize(streamPayload, input, typeof(T), default);
Comment thread
kirankumarkolli marked this conversation as resolved.
streamPayload.Position = 0;
return streamPayload;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ namespace Microsoft.Azure.Cosmos.Services.Management.Tests
using Microsoft.Azure.Documents;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;

internal class LinqTestsCommon
{
/// <summary>
Expand All @@ -36,18 +36,18 @@ internal class LinqTestsCommon
/// <param name="dataResults"></param>
/// <returns></returns>
private static bool CompareListOfAnonymousType(List<object> queryResults, List<dynamic> dataResults, bool ignoreOrder)
{
if (!ignoreOrder)
{
return queryResults.SequenceEqual(dataResults);
}
if (queryResults.Count != dataResults.Count)
{
return false;
}
bool resultMatched = true;
{
if (!ignoreOrder)
{
return queryResults.SequenceEqual(dataResults);
}

if (queryResults.Count != dataResults.Count)
{
return false;
}

bool resultMatched = true;
foreach (object obj in queryResults)
{
if (!dataResults.Any(a => a.Equals(obj)))
Expand All @@ -64,8 +64,8 @@ private static bool CompareListOfAnonymousType(List<object> queryResults, List<d
resultMatched = false;
break;
}
}
}

return resultMatched;
}

Expand Down Expand Up @@ -533,15 +533,15 @@ Family createDataObj(Random random)
return getQuery;
}

public static Func<bool, IQueryable<Data>> GenerateSimpleCosmosData(Cosmos.Database cosmosDatabase, bool useRandomData = true)
public static Func<bool, IQueryable<Data>> GenerateSimpleCosmosData(Cosmos.Database cosmosDatabase, bool useRandomData = true)
{
const int DocumentCount = 10;
PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection<string>(new[] { "/Pk" }), Kind = PartitionKind.Hash };
Container container = cosmosDatabase.CreateContainerAsync(new ContainerProperties { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }).Result;

ILinqTestDataGenerator dataGenerator = useRandomData ? new LinqTestRandomDataGenerator(DocumentCount) : new LinqTestDataGenerator(DocumentCount);
List<Data> testData = new List<Data>(dataGenerator.GenerateData());
foreach (Data dataEntry in testData)
ILinqTestDataGenerator dataGenerator = useRandomData ? new LinqTestRandomDataGenerator(DocumentCount) : new LinqTestDataGenerator(DocumentCount);
List<Data> testData = new List<Data>(dataGenerator.GenerateData());
foreach (Data dataEntry in testData)
{
Data response = container.CreateItemAsync<Data>(dataEntry, new Cosmos.PartitionKey(dataEntry.Pk)).Result;
}
Expand Down Expand Up @@ -593,32 +593,32 @@ public static LinqTestOutput ExecuteTest(LinqTestInput input, bool serializeResu
}

public static string BuildExceptionMessageForTest(Exception ex)
{
StringBuilder message = new StringBuilder();
{
StringBuilder message = new StringBuilder();
do
{
if (ex is CosmosException cosmosException)
{
message.Append($"Status Code: {cosmosException.StatusCode}");
{
message.Append($"Status Code: {cosmosException.StatusCode}");
}
else if (ex is DocumentClientException documentClientException)
{
message.Append(documentClientException.RawErrorMessage);
}
else
{
message.Append(ex.Message);
{
message.Append(ex.Message);
}

ex = ex.InnerException;
if (ex != null)
{
message.Append(",");
}
}
while (ex != null);
return message.ToString();
while (ex != null);

return message.ToString();
}
}

Expand Down Expand Up @@ -675,27 +675,27 @@ public class LinqTestInput : BaselineTestInput
// - unordered query since the results are not deterministics for LinQ results and actual query results
// - scenarios not supported in LINQ, e.g. sequence doesn't contain element.
internal bool skipVerification;
// Ignore Ordering for AnonymousType object
internal bool ignoreOrder;
internal bool serializeOutput;

// Ignore Ordering for AnonymousType object
internal bool ignoreOrder;

internal bool serializeOutput;

internal LinqTestInput(
string description,
Expression<Func<bool, IQueryable>> expr,
bool skipVerification = false,
bool skipVerification = false,
bool ignoreOrder = false,
string expressionStr = null,
string inputData = null,
string inputData = null,
bool serializeOutput = false)
: base(description)
{
this.Expression = expr ?? throw new ArgumentNullException($"{nameof(expr)} must not be null.");
this.skipVerification = skipVerification;
this.skipVerification = skipVerification;
this.ignoreOrder = ignoreOrder;
this.expressionStr = expressionStr;
this.inputData = inputData;
this.inputData = inputData;
this.serializeOutput = serializeOutput;
}

Expand Down Expand Up @@ -761,7 +761,7 @@ public class LinqTestOutput : BaselineTestOutput
{ "WHERE", "\nWHERE" },
{ "JOIN", "\nJOIN" },
{ "ORDER BY", "\nORDER BY" },
{ "OFFSET", "\nOFFSET" },
{ "OFFSET", "\nOFFSET" },
{ "GROUP BY", "\nGROUP BY" },
{ " )", "\n)" }
};
Expand Down Expand Up @@ -852,14 +852,14 @@ public override void SerializeAsXml(XmlWriter xmlWriter)
}
}

class SystemTextJsonLinqSerializer : CosmosLinqSerializer
internal class SystemTextJsonLinqSerializer : CosmosLinqSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;
private readonly JsonObjectSerializer systemTextJsonSerializer;
private readonly JsonSerializerOptions jsonSerializerOptions;

public SystemTextJsonLinqSerializer(JsonSerializerOptions jsonSerializerOptions)
{
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
this.jsonSerializerOptions = jsonSerializerOptions;
}

Expand Down Expand Up @@ -894,66 +894,27 @@ public override Stream ToStream<T>(T input)

public override string SerializeMemberName(MemberInfo memberInfo)
{
System.Text.Json.Serialization.JsonExtensionDataAttribute jsonExtensionDataAttribute =
memberInfo.GetCustomAttribute<System.Text.Json.Serialization.JsonExtensionDataAttribute>(true);
if (jsonExtensionDataAttribute != null)
{
return null;
}

JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name))
{
return jsonPropertyNameAttribute.Name;
}

if (this.jsonSerializerOptions.PropertyNamingPolicy != null)
{
return this.jsonSerializerOptions.PropertyNamingPolicy.ConvertName(memberInfo.Name);
}

// Do any additional handling of JsonSerializerOptions here.

return memberInfo.Name;
}
}

class SystemTextJsonSerializer : CosmosSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;

public SystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
{
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
}

public override T FromStream<T>(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));

using (stream)
System.Text.Json.Serialization.JsonExtensionDataAttribute jsonExtensionDataAttribute =
memberInfo.GetCustomAttribute<System.Text.Json.Serialization.JsonExtensionDataAttribute>(true);
if (jsonExtensionDataAttribute != null)
{
if (stream.CanSeek && stream.Length == 0)
{
return default;
}
return null;
}

if (typeof(Stream).IsAssignableFrom(typeof(T)))
{
return (T)(object)stream;
}
JsonPropertyNameAttribute jsonPropertyNameAttribute = memberInfo.GetCustomAttribute<JsonPropertyNameAttribute>(true);
if (!string.IsNullOrEmpty(jsonPropertyNameAttribute?.Name))
{
return jsonPropertyNameAttribute.Name;
}

return (T)this.systemTextJsonSerializer.Deserialize(stream, typeof(T), default);
if (this.jsonSerializerOptions.PropertyNamingPolicy != null)
{
return this.jsonSerializerOptions.PropertyNamingPolicy.ConvertName(memberInfo.Name);
}
}

public override Stream ToStream<T>(T input)
{
MemoryStream streamPayload = new MemoryStream();
this.systemTextJsonSerializer.Serialize(streamPayload, input, input.GetType(), default);
streamPayload.Position = 0;
return streamPayload;
// Do any additional handling of JsonSerializerOptions here.

return memberInfo.Name;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//-----------------------------------------------------------------------
// <copyright file="SystemTextJsonSerializer.cs" company="Microsoft Corporation">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.Azure.Cosmos.Services.Management.Tests
{
using System;
using System.IO;
using System.Text.Json;
using global::Azure.Core.Serialization;

internal class SystemTextJsonSerializer : CosmosSerializer
{
private readonly JsonObjectSerializer systemTextJsonSerializer;

public SystemTextJsonSerializer(JsonSerializerOptions jsonSerializerOptions)
{
this.systemTextJsonSerializer = new JsonObjectSerializer(jsonSerializerOptions);
}

public override T FromStream<T>(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));

using (stream)
{
if (stream.CanSeek && stream.Length == 0)
{
return default;
}

if (typeof(Stream).IsAssignableFrom(typeof(T)))
{
return (T)(object)stream;
}

return (T)this.systemTextJsonSerializer.Deserialize(stream, typeof(T), default);
}
}

public override Stream ToStream<T>(T input)
{
MemoryStream streamPayload = new MemoryStream();
this.systemTextJsonSerializer.Serialize(streamPayload, input, typeof(T), default);
streamPayload.Position = 0;
return streamPayload;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using Microsoft.Azure.Cosmos.Tests.Poco.STJ;
using Microsoft.VisualStudio.TestTools.UnitTesting;

Expand Down Expand Up @@ -176,5 +177,54 @@ public void TestSerializeMemberName()
Assert.AreEqual(member.Name, this.stjSerializer.SerializeMemberName(member));
}
}

[TestMethod]
public void TestPolymorphicSerialization_IncludesTypeDiscriminator()
{
// Arrange.
Shape circle = new Circle
{
Id = "circle",
Color = "Red",
Radius = 5.0
};

// Act.
Stream serializedStream = this.stjSerializer.ToStream(circle);
using StreamReader reader = new(serializedStream);
string json = reader.ReadToEnd();

// Assert.
using JsonDocument jsonDocument = JsonDocument.Parse(json);
JsonElement rootElement = jsonDocument.RootElement;

Assert.AreEqual("Circle", rootElement.GetProperty("$type").GetString());
Assert.AreEqual(5.0, rootElement.GetProperty("radius").GetDouble());
}

[TestMethod]
public void TestPolymorphicSerialization_SerializeDeserialize_PreservesType()
{
// Arrange.
Shape original = new Circle
{
Id = "circle",
Color = "Green",
Radius = 7.5
};

// Act.
Stream serializedStream = this.stjSerializer.ToStream(original);
Shape deserialized = this.stjSerializer.FromStream<Shape>(serializedStream);

// Assert.
Assert.IsNotNull(deserialized);
Assert.IsInstanceOfType(deserialized, typeof(Circle));

Circle deserializedCircle = (Circle)deserialized;
Assert.AreEqual(original.Id, deserializedCircle.Id);
Assert.AreEqual(original.Color, deserializedCircle.Color);
Assert.AreEqual(((Circle)original).Radius, deserializedCircle.Radius);
}
}
}
Loading
Loading