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
7 changes: 5 additions & 2 deletions sdk/core/Azure.Core/src/Shared/ModelSerializerHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ namespace Azure.Core
internal static class ModelSerializerHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateFormat(IModelSerializable<object> model, ModelSerializerFormat format)
public static void ValidateFormat<T>(IModelSerializable<T> model, ModelSerializerFormat format)
{
bool implementsJson = model is IModelJsonSerializable<object>;
bool implementsJson = model is IModelJsonSerializable<T>;
bool isValid = (format == ModelSerializerFormat.Json && implementsJson) || format == ModelSerializerFormat.Wire;
if (!isValid)
{
throw new NotSupportedException($"The model {model.GetType().Name} does not support '{format}' format.");
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidateFormat(IModelSerializable<object> model, ModelSerializerFormat format) => ValidateFormat<object>(model, format);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ public static implicit operator RequestContent(BaseModel baseModel)

public static explicit operator BaseModel(Response response)
{
if (response == null)
{
return null;
}
Argument.AssertNotNull(response, nameof(response));

using JsonDocument jsonDocument = JsonDocument.Parse(response.ContentStream);
return DeserializeBaseModel(jsonDocument.RootElement, ModelSerializerOptions.DefaultWireOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ public static implicit operator RequestContent(ModelX modelX)

public static explicit operator ModelX(Response response)
{
if (response == null)
{
return null;
}
Argument.AssertNotNull(response, nameof(response));

using JsonDocument jsonDocument = JsonDocument.Parse(response.ContentStream);
return DeserializeModelX(jsonDocument.RootElement, ModelSerializerOptions.DefaultWireOptions);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#nullable disable

using System;
using System.Collections.Generic;
using System.Text.Json;
using Azure.Core.Serialization;

namespace Azure.Core.Tests.ModelSerializationTests.Models
{
/// <summary> The InputAdditionalPropertiesModelStruct. </summary>
public readonly partial struct ModelAsStruct : IUtf8JsonSerializable, IModelJsonSerializable<ModelAsStruct>, IModelJsonSerializable<object>
{
private readonly Dictionary<string, BinaryData> _rawData;

/// <summary> Initializes a new instance of InputAdditionalPropertiesModelStruct. </summary>
/// <param name="id"></param>
/// <param name="additionalProperties"> Additional Properties. </param>
/// <param name="rawData"></param>
/// <exception cref="ArgumentNullException"> <paramref name="additionalProperties"/> is null. </exception>
public ModelAsStruct(int id, Dictionary<string, BinaryData> rawData)
{
Id = id;
_rawData = rawData;
}

/// <summary> Gets the id. </summary>
public int Id { get; }

void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IModelJsonSerializable<ModelAsStruct>)this).Serialize(writer, ModelSerializerOptions.DefaultWireOptions);

void IModelJsonSerializable<ModelAsStruct>.Serialize(Utf8JsonWriter writer, ModelSerializerOptions options) => Serialize(writer, options);

private void Serialize(Utf8JsonWriter writer, ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

writer.WriteStartObject();
writer.WritePropertyName("id"u8);
writer.WriteNumberValue(Id);
if (_rawData is not null && options.Format == ModelSerializerFormat.Json)
{
foreach (var property in _rawData)
{
writer.WritePropertyName(property.Key);
#if NET6_0_OR_GREATER
writer.WriteRawValue(property.Value);
#else
JsonSerializer.Serialize(writer, JsonDocument.Parse(property.Value.ToString()).RootElement);
#endif
}
}
writer.WriteEndObject();
}

BinaryData IModelSerializable<ModelAsStruct>.Serialize(ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using ModelWriter writer = new ModelWriter(this, options);
return writer.ToBinaryData();
}

public static implicit operator RequestContent(ModelAsStruct model)
{
return RequestContent.Create(model, ModelSerializerOptions.DefaultWireOptions);
}

ModelAsStruct IModelSerializable<ModelAsStruct>.Deserialize(BinaryData data, ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using var doc = JsonDocument.Parse(data);
return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, options);
}

internal static ModelAsStruct DeserializeInputAdditionalPropertiesModelStruct(JsonElement element, ModelSerializerOptions options = default)
{
options ??= ModelSerializerOptions.DefaultWireOptions;

int id = default;
Dictionary<string, BinaryData> rawData = new Dictionary<string, BinaryData>();
foreach (var property in element.EnumerateObject())
{
if (property.NameEquals("id"u8))
{
id = property.Value.GetInt32();
continue;
}
if (options.Format == ModelSerializerFormat.Json)
{
rawData.Add(property.Name, BinaryData.FromString(property.Value.GetRawText()));
continue;
}
}
return new ModelAsStruct(id, rawData);
}

ModelAsStruct IModelJsonSerializable<ModelAsStruct>.Deserialize(ref Utf8JsonReader reader, ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using var doc = JsonDocument.ParseValue(ref reader);
return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, options);
}

public static explicit operator ModelAsStruct(Response response)
{
Argument.AssertNotNull(response, nameof(response));

using JsonDocument doc = JsonDocument.Parse(response.ContentStream);
return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, ModelSerializerOptions.DefaultWireOptions);
}

void IModelJsonSerializable<object>.Serialize(Utf8JsonWriter writer, ModelSerializerOptions options) => Serialize(writer, options);

object IModelJsonSerializable<object>.Deserialize(ref Utf8JsonReader reader, ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using var doc = JsonDocument.ParseValue(ref reader);
return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, options);
}

BinaryData IModelSerializable<object>.Serialize(ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using ModelWriter writer = new ModelWriter(this, options);
return writer.ToBinaryData();
}

object IModelSerializable<object>.Deserialize(BinaryData data, ModelSerializerOptions options)
{
ModelSerializerHelper.ValidateFormat<ModelAsStruct>(this, options.Format);

using var doc = JsonDocument.Parse(data);
return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@ public static implicit operator RequestContent(ModelXml modelXml)

public static explicit operator ModelXml(Response response)
{
if (response == null)
{
return null;
}
Argument.AssertNotNull(response, nameof(response));

return DeserializeModelXml(XElement.Load(response.ContentStream), ModelSerializerOptions.DefaultWireOptions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ public static implicit operator RequestContent(AvailabilitySetData availabilityS

public static explicit operator AvailabilitySetData(Response response)
{
if (response is null)
{
return null;
}
Argument.AssertNotNull(response, nameof(response));

using JsonDocument jsonDocument = JsonDocument.Parse(response.ContentStream);
return DeserializeAvailabilitySetData(jsonDocument.RootElement, ModelSerializerOptions.DefaultWireOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@ public static implicit operator RequestContent(ResourceProviderData resourceProv

public static explicit operator ResourceProviderData(Response response)
{
if (response == null)
{
return null;
}
Argument.AssertNotNull(response, nameof(response));

using JsonDocument jsonDocument = JsonDocument.Parse(response.ContentStream);
return DeserializeResourceProviderData(jsonDocument.RootElement, ModelSerializerOptions.DefaultWireOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Azure.Core.Tests.Public.ModelSerializationTests
{
internal class AvailabilitySetDataTests : ModelTests<AvailabilitySetData>
internal class AvailabilitySetDataTests : ModelJsonTests<AvailabilitySetData>
{
protected override string WirePayload => "{\"name\":\"testAS-3375\",\"id\":\"/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375\",\"type\":\"Microsoft.Compute/availabilitySets\",\"location\":\"eastus\",\"tags\":{\"key\":\"value\"},\"properties\":{\"platformUpdateDomainCount\":5,\"platformFaultDomainCount\":3},\"sku\":{\"name\":\"Classic\",\"extraSku\":\"extraSku\"},\"extraRoot\":\"extraRoot\"}";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Azure.Core.Tests.Public.ModelSerializationTests
{
internal class BaseModelTests : ModelTests<BaseModel>
internal class BaseModelTests : ModelJsonTests<BaseModel>
{
protected override BaseModel GetModelInstance()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Azure.Core.Tests.Public.ModelSerializationTests
{
internal class EnvelopeTests : ModelTests<Envelope<EnvelopeTests.ModelC>>
internal class EnvelopeTests : ModelJsonTests<Envelope<EnvelopeTests.ModelC>>
{
protected override string JsonPayload => WirePayload;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using Azure.Core.Serialization;
using Azure.Core.Tests.ModelSerializationTests.Models;
using NUnit.Framework;

namespace Azure.Core.Tests.Public.ModelSerializationTests
{
internal class ModelAsStructTests : ModelJsonTests<ModelAsStruct>
{
protected override string JsonPayload => WirePayload;

protected override string WirePayload => "{\"id\":5,\"extra\":\"stuff\"}";

protected override Func<ModelAsStruct, RequestContent> ToRequestContent => model => model;

protected override Func<Response, ModelAsStruct> FromResponse => response => (ModelAsStruct)response;

protected override void CompareModels(ModelAsStruct model, ModelAsStruct model2, ModelSerializerFormat format)
{
Assert.AreEqual(model.Id, model2.Id);
var rawData1 = GetRawData(model);
var rawData2 = GetRawData(model2);
Assert.IsNotNull(rawData1);
Assert.IsNotNull(rawData2);
if (format == ModelSerializerFormat.Json)
Assert.AreEqual(rawData1["extra"].ToObjectFromJson<string>(), rawData2["extra"].ToObjectFromJson<string>());
}

protected override string GetExpectedResult(ModelSerializerFormat format)
{
string expected = "{\"id\":5";
if (format == ModelSerializerFormat.Json)
expected += ",\"extra\":\"stuff\"";
expected += "}";
return expected;
}

protected override void VerifyModel(ModelAsStruct model, ModelSerializerFormat format)
{
Assert.AreEqual(5, model.Id);
var rawData = GetRawData(model);
Assert.IsNotNull(rawData);
if (format == ModelSerializerFormat.Json)
Assert.AreEqual("stuff", rawData["extra"].ToObjectFromJson<string>());
}
}
}
Loading