Skip to content

Commit 648a215

Browse files
m-nashchristothes
andauthored
Update to BinaryData deserializer to support Any and AnyObject (Azure#27599)
* update to BinaryData deserializer to support Any and AnyObject * update api * update test case for net461 * clean up test case from comments * update test references * missed using * Update sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs Co-authored-by: Christopher Scott <chriss@microsoft.com> * update comment Co-authored-by: Christopher Scott <chriss@microsoft.com>
1 parent a6f1d7a commit 648a215

16 files changed

+198
-19
lines changed

sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineTestBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ protected async Task<GenericResource> CreateVirtualNetwork()
6464

6565
protected ResourceIdentifier GetSubnetId(GenericResource vnet)
6666
{
67-
var properties = vnet.Data.Properties.ToDictionaryFromJson();
67+
var properties = vnet.Data.Properties.ToObjectFromJson() as Dictionary<string, object>;
6868
var subnets = properties["subnets"] as IEnumerable<object>;
6969
var subnet = subnets.First() as IDictionary<string, object>;
7070
return new ResourceIdentifier(subnet["id"] as string);

sdk/core/Azure.Core/api/Azure.Core.net461.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
1717
}
1818
public static partial class AzureCoreExtensions
1919
{
20-
public static System.Collections.Generic.IDictionary<string, object?> ToDictionaryFromJson(this System.BinaryData data) { throw null; }
2120
public static System.Threading.Tasks.ValueTask<T?> ToObjectAsync<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
21+
public static object? ToObjectFromJson(this System.BinaryData data) { throw null; }
2222
public static T? ToObject<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
2323
}
2424
public partial class AzureKeyCredential

sdk/core/Azure.Core/api/Azure.Core.net5.0.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
1717
}
1818
public static partial class AzureCoreExtensions
1919
{
20-
public static System.Collections.Generic.IDictionary<string, object?> ToDictionaryFromJson(this System.BinaryData data) { throw null; }
2120
public static System.Threading.Tasks.ValueTask<T?> ToObjectAsync<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
21+
public static object? ToObjectFromJson(this System.BinaryData data) { throw null; }
2222
public static T? ToObject<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
2323
}
2424
public partial class AzureKeyCredential

sdk/core/Azure.Core/api/Azure.Core.netcoreapp2.1.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
1717
}
1818
public static partial class AzureCoreExtensions
1919
{
20-
public static System.Collections.Generic.IDictionary<string, object?> ToDictionaryFromJson(this System.BinaryData data) { throw null; }
2120
public static System.Threading.Tasks.ValueTask<T?> ToObjectAsync<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
21+
public static object? ToObjectFromJson(this System.BinaryData data) { throw null; }
2222
public static T? ToObject<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
2323
}
2424
public partial class AzureKeyCredential

sdk/core/Azure.Core/api/Azure.Core.netstandard2.0.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ protected AsyncPageable(System.Threading.CancellationToken cancellationToken) {
1717
}
1818
public static partial class AzureCoreExtensions
1919
{
20-
public static System.Collections.Generic.IDictionary<string, object?> ToDictionaryFromJson(this System.BinaryData data) { throw null; }
2120
public static System.Threading.Tasks.ValueTask<T?> ToObjectAsync<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
21+
public static object? ToObjectFromJson(this System.BinaryData data) { throw null; }
2222
public static T? ToObject<T>(this System.BinaryData data, Azure.Core.Serialization.ObjectSerializer serializer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
2323
}
2424
public partial class AzureKeyCredential

sdk/core/Azure.Core/perf/DynamicObjectBenchmark.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public void DeserializeWithBinaryData()
8888
public void DeserializeWithBinaryDataAndAccess()
8989
{
9090
var model = ModelWithBinaryData.DeserializeModelWithBinaryData(_jsonDocument.RootElement);
91-
var properties = model.Properties.ToDictionaryFromJson();
91+
var properties = model.Properties.ToObjectFromJson() as Dictionary<string, object>;
9292
var innerProperties = properties["innerProperties"] as Dictionary<string, object>;
9393
var innerA = innerProperties["a"] as string;
9494
}

sdk/core/Azure.Core/src/Serialization/AzureCoreExtensions.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,18 @@ public static class AzureCoreExtensions
4444
(T?)await serializer.DeserializeAsync(data.ToStream(), typeof(T), cancellationToken).ConfigureAwait(false);
4545

4646
/// <summary>
47-
/// Converts the <see cref="BinaryData"/> to a Dictionary of string to object.
48-
/// Each value in the key value pair will be strongly typed as an int, long, string, Guid, double or bool.
49-
/// Each value can also be another Dictionary of string object representing an inner object or
50-
/// a List of objects representing an array.
47+
/// Converts the json value represented by <see cref="BinaryData"/> to an object of a specific type.
5148
/// </summary>
5249
/// <param name="data">The <see cref="BinaryData"/> instance to convert.</param>
53-
/// <returns>The data converted to the Dictionary of string to object.</returns>
54-
public static IDictionary<string, object?> ToDictionaryFromJson(this BinaryData data)
50+
/// <returns> The object value of the json value.
51+
/// If the object contains a primitive type such as string, int, double, bool, or null literal, it returns that type.
52+
/// Otherwise, it returns either an object[] or Dictionary&lt;string, object&gt;.
53+
/// Each value in the key value pair or list will also be converted into a primitive or another complex type recursively.
54+
/// </returns>
55+
public static object? ToObjectFromJson(this BinaryData data)
5556
{
5657
JsonElement element = data.ToObjectFromJson<JsonElement>();
57-
return element.GetObject() as Dictionary<string, object?> ?? throw new InvalidOperationException("The BinaryData instance did not represent a JSON object so it cannot be converted into a dictionary.");
58+
return element.GetObject();
5859
}
5960

6061
private static object? GetObject(in this JsonElement element)

sdk/core/Azure.Core/tests/BinaryDataSerializationTests.cs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,74 @@ namespace Azure.Core.Tests
1616
{
1717
public class BinaryDataSerializationTests
1818
{
19+
[Test]
20+
public void DeserializeModelWithDictionaryOfBinaryData()
21+
{
22+
using var fs = File.Open(GetFileName("JsonFormattedStringDictOfBinaryData.json"), FileMode.Open, FileAccess.Read, FileShare.Read);
23+
using var document = JsonDocument.Parse(fs);
24+
var data = ModelWithBinaryDataInDictionary.DeserializeModelWithBinaryDataInDictionary(document.RootElement);
25+
26+
Assert.AreEqual("a.value", data.A);
27+
Assert.AreEqual("1", data.Details["strValue"].ToObjectFromJson<string>());
28+
Assert.IsTrue(data.Details["strValue"].ToObjectFromJson() is string);
29+
Assert.AreEqual(1, data.Details["intValue"].ToObjectFromJson<int>());
30+
Assert.IsTrue(data.Details["intValue"].ToObjectFromJson() is int);
31+
Assert.AreEqual(1.1, data.Details["doubleValue"].ToObjectFromJson<double>());
32+
Assert.IsTrue(data.Details["doubleValue"].ToObjectFromJson() is double);
33+
34+
var toObjectWithT = data.Details["innerProperties"].ToObjectFromJson<Dictionary<string, object>>();
35+
var jsonElementObject = data.Details["innerProperties"].ToObjectFromJson<object>();
36+
Assert.IsTrue(jsonElementObject is JsonElement);
37+
var jsonDictionary = data.Details["innerProperties"].ToObjectFromJson();
38+
Assert.IsTrue(jsonDictionary is Dictionary<string, object>);
39+
Assert.IsTrue(toObjectWithT["strValue"] is JsonElement);
40+
41+
var dict = data.Details["innerProperties"].ToObjectFromJson() as Dictionary<string, object>;
42+
Assert.AreEqual("2", (string)dict["strValue"]);
43+
Assert.AreEqual(2, (int)dict["intValue"]);
44+
Assert.AreEqual(2.2, (double)dict["doubleValue"]);
45+
}
46+
47+
[Test]
48+
public void CanConvertInt()
49+
{
50+
using var fs = File.Open(GetFileName("JsonFormattedStringInt.json"), FileMode.Open, FileAccess.Read, FileShare.Read);
51+
using var document = JsonDocument.Parse(fs);
52+
var data = ModelWithBinaryData.DeserializeModelWithBinaryData(document.RootElement);
53+
54+
Assert.AreEqual("a.value", data.A);
55+
Assert.AreEqual(1, data.Properties.ToObjectFromJson<int>());
56+
}
57+
58+
[Test]
59+
public void CanConvertDouble()
60+
{
61+
using var fs = File.Open(GetFileName("JsonFormattedStringDouble.json"), FileMode.Open, FileAccess.Read, FileShare.Read);
62+
using var document = JsonDocument.Parse(fs);
63+
var data = ModelWithBinaryData.DeserializeModelWithBinaryData(document.RootElement);
64+
65+
Assert.AreEqual("a.value", data.A);
66+
Assert.AreEqual(1.1, data.Properties.ToObjectFromJson<double>());
67+
}
68+
69+
[Test]
70+
public void CanConvertString()
71+
{
72+
using var fs = File.Open(GetFileName("JsonFormattedStringString.json"), FileMode.Open, FileAccess.Read, FileShare.Read);
73+
using var document = JsonDocument.Parse(fs);
74+
var data = ModelWithBinaryData.DeserializeModelWithBinaryData(document.RootElement);
75+
76+
Assert.AreEqual("a.value", data.A);
77+
Assert.AreEqual("1", data.Properties.ToObjectFromJson<string>());
78+
}
79+
1980
[Test]
2081
public void CanConvertDifferentValueTypes()
2182
{
2283
var expected = File.ReadAllText(GetFileName("PropertiesWithDifferentValueTypes.json")).TrimEnd();
2384
var model = BinaryData.FromString(expected);
2485

25-
var properties = model.ToDictionaryFromJson();
86+
var properties = model.ToObjectFromJson() as Dictionary<string, object>;
2687
Assert.AreEqual(typeof(string), properties["stringValue"].GetType());
2788
Assert.AreEqual(typeof(string), properties["dateTimeValue"].GetType());
2889
Assert.AreEqual(typeof(int), properties["intValue"].GetType());
@@ -41,7 +102,7 @@ public void CanConvertArrays()
41102
var expected = File.ReadAllText(GetFileName("PropertiesWithArrays.json")).TrimEnd();
42103
var model = BinaryData.FromString(expected);
43104

44-
var properties = model.ToDictionaryFromJson();
105+
var properties = model.ToObjectFromJson() as Dictionary<string, object>;
45106
Assert.IsTrue(AllValuesAreType(typeof(string), properties["stringArray"]));
46107
Assert.IsTrue(AllValuesAreType(typeof(string), properties["dateTimeArray"]));
47108
Assert.IsTrue(AllValuesAreType(typeof(int), properties["intArray"]));
@@ -72,7 +133,7 @@ public void CanConvertArrayOfObjects()
72133
{
73134
var expected = File.ReadAllText(GetFileName("PropertiesWithArraysOfObjects.json")).TrimEnd();
74135
var model = BinaryData.FromString(expected);
75-
var properties = model.ToDictionaryFromJson();
136+
var properties = model.ToObjectFromJson() as Dictionary<string, object>;
76137
var objArray = properties["objectArray"] as object[];
77138
for (int i = 0; i < 3; i++)
78139
{
@@ -91,7 +152,7 @@ public void CanConvertArrayOfArrays()
91152
{
92153
var expected = File.ReadAllText(GetFileName("PropertiesWithArraysOfArrays.json")).TrimEnd();
93154
var model = BinaryData.FromString(expected);
94-
var properties = model.ToDictionaryFromJson();
155+
var properties = model.ToObjectFromJson() as Dictionary<string, object>;
95156
var arrayArray = properties["arrayArray"] as object[];
96157
Assert.IsNotNull(arrayArray);
97158
for (int i = 0; i < 2; i++)
@@ -141,7 +202,7 @@ public void DeserializeJsonFormattedStringWithBinaryData()
141202
var data = ModelWithBinaryData.DeserializeModelWithBinaryData(document.RootElement);
142203
Assert.AreEqual("a.value", data.A);
143204

144-
var properties = data.Properties.ToDictionaryFromJson();
205+
var properties = data.Properties.ToObjectFromJson() as Dictionary<string, object>;
145206
Assert.AreEqual("properties.a.value", properties["a"]);
146207
var innerProperties = properties["innerProperties"] as IDictionary<string, object>;
147208
Assert.AreEqual("properties.innerProperties.a.value", innerProperties["a"]);
@@ -177,6 +238,34 @@ public void SerailizeUsingJsonFormattedString()
177238
Assert.AreEqual(expected, actual);
178239
}
179240

241+
[Test]
242+
public void SerailizeUsingJsonFormattedStringForDictOfBinaryData()
243+
{
244+
#if NET461
245+
var expected = File.ReadAllText(GetFileName("JsonFormattedStringDictOfBinaryDataNet461.json")).TrimEnd();
246+
#else
247+
var expected = File.ReadAllText(GetFileName("JsonFormattedStringDictOfBinaryData.json")).TrimEnd();
248+
#endif
249+
250+
var payload = new ModelWithBinaryDataInDictionary { A = "a.value" };
251+
252+
var details = new Dictionary<string, BinaryData>();
253+
details["strValue"] = BinaryData.FromObjectAsJson("1");
254+
details["intValue"] = BinaryData.FromObjectAsJson(1);
255+
details["doubleValue"] = BinaryData.FromObjectAsJson(1.1);
256+
257+
var innerProperties = new Dictionary<string, object>();
258+
innerProperties["strValue"] = "2";
259+
innerProperties["intValue"] = 2;
260+
innerProperties["doubleValue"] = 2.2;
261+
262+
details["innerProperties"] = BinaryData.FromObjectAsJson(innerProperties);
263+
payload.Details = details;
264+
265+
string actual = GetSerializedString(payload);
266+
Assert.AreEqual(expected, actual);
267+
}
268+
180269
[Test]
181270
public void SerailizeUsingStream()
182271
{
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using Azure.Core;
6+
using System.Text.Json;
7+
using System.IO;
8+
using System.Collections.Generic;
9+
10+
namespace Azure.Core.Tests
11+
{
12+
internal class ModelWithBinaryDataInDictionary : IUtf8JsonSerializable
13+
{
14+
public string A { get; set; }
15+
public IReadOnlyDictionary<string, BinaryData> Details { get; set; }
16+
17+
public ModelWithBinaryDataInDictionary() { }
18+
19+
private ModelWithBinaryDataInDictionary(string a, IReadOnlyDictionary<string, BinaryData> details)
20+
{
21+
A = a;
22+
Details = details;
23+
}
24+
25+
public void Write(Utf8JsonWriter writer)
26+
{
27+
writer.WriteStartObject();
28+
if (Optional.IsDefined(A))
29+
{
30+
writer.WritePropertyName("a");
31+
writer.WriteStringValue(A);
32+
}
33+
if (Optional.IsDefined(Details))
34+
{
35+
//THIS DOESN'T WORK WITH OUR CURRENT AUTOREST
36+
writer.WritePropertyName("details");
37+
writer.WriteStartObject();
38+
foreach (var kv in Details)
39+
{
40+
writer.WritePropertyName(kv.Key);
41+
#if NET6_0_OR_GREATER
42+
writer.WriteRawValue(kv.Value);
43+
#else
44+
JsonSerializer.Serialize(writer, JsonDocument.Parse(kv.Value.ToString()).RootElement);
45+
#endif
46+
}
47+
writer.WriteEndObject();
48+
}
49+
writer.WriteEndObject();
50+
}
51+
52+
internal static ModelWithBinaryDataInDictionary DeserializeModelWithBinaryDataInDictionary(JsonElement element)
53+
{
54+
Optional<string> a = default;
55+
Optional<IReadOnlyDictionary<string, BinaryData>> details = default;
56+
foreach (var property in element.EnumerateObject())
57+
{
58+
if (property.NameEquals("a"))
59+
{
60+
a = property.Value.GetString();
61+
continue;
62+
}
63+
if (property.NameEquals("details"))
64+
{
65+
if (property.Value.ValueKind == JsonValueKind.Null)
66+
{
67+
property.ThrowNonNullablePropertyIsNull();
68+
continue;
69+
}
70+
Dictionary<string, BinaryData> dictionary = new Dictionary<string, BinaryData>();
71+
foreach (var property1 in property.Value.EnumerateObject())
72+
{
73+
dictionary.Add(property1.Name, BinaryData.FromString(property1.Value.GetRawText()));
74+
}
75+
details = dictionary;
76+
continue;
77+
}
78+
}
79+
return new ModelWithBinaryDataInDictionary(a.Value, details.Value);
80+
}
81+
}
82+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"a":"a.value","details":{"strValue":"1","intValue":1,"doubleValue":1.1,"innerProperties":{"strValue":"2","intValue":2,"doubleValue":2.2}}}

0 commit comments

Comments
 (0)