Skip to content

Commit f3995c1

Browse files
authored
Implement resource serialization (#50229)
1 parent aca90d2 commit f3995c1

27 files changed

+1438
-101
lines changed

eng/Packages.Data.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,6 @@
439439
<PropertyGroup>
440440
<TestProxyVersion>1.0.0-dev.20250501.1</TestProxyVersion>
441441
<UnbrandedGeneratorVersion>1.0.0-alpha.20250523.1</UnbrandedGeneratorVersion>
442-
<AzureGeneratorVersion>1.0.0-alpha.20250515.2</AzureGeneratorVersion>
442+
<AzureGeneratorVersion>1.0.0-alpha.20250523.1</AzureGeneratorVersion>
443443
</PropertyGroup>
444444
</Project>

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementOutputLibrary.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,14 @@ private static void BuildResourceCore(List<ResourceClientProvider> resources, Li
5050
protected override TypeProvider[] BuildTypeProviders()
5151
{
5252
var (resources, collections) = BuildResources();
53-
return [.. base.BuildTypeProviders().Where(t => t is not InheritableSystemObjectModelProvider), ArmOperation, GenericArmOperation, .. resources, .. collections, .. resources.Select(r => r.Source)];
53+
return [
54+
.. base.BuildTypeProviders().Where(t => t is not InheritableSystemObjectModelProvider),
55+
ArmOperation,
56+
GenericArmOperation,
57+
.. resources,
58+
.. collections,
59+
.. resources.Select(r => r.Source),
60+
.. resources.SelectMany(r => r.SerializationProviders)];
5461
}
5562
}
5663
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceClientProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ protected override PropertyProvider[] BuildProperties()
118118
return [hasDataProperty, dataProperty];
119119
}
120120

121+
protected override TypeProvider[] BuildSerializationProviders() => [new ResourceSerializationProvider(this)];
122+
121123
protected override ConstructorProvider[] BuildConstructors()
122124
=> [ConstructorProviderHelper.BuildMockingConstructor(this), BuildResourceDataConstructor(), BuildResourceIdentifierConstructor()];
123125

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Providers/ResourceCollectionClientProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public ResourceCollectionClientProvider(InputClient inputClient, ResourceMetadat
5252
}
5353
}
5454

55+
protected override TypeProvider[] BuildSerializationProviders() => [];
56+
5557
protected override string BuildName() => $"{SpecName}Collection";
5658

5759
protected override CSharpType[] BuildImplements() =>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.TypeSpec.Generator.ClientModel.Snippets;
5+
using Microsoft.TypeSpec.Generator.Expressions;
6+
using Microsoft.TypeSpec.Generator.Primitives;
7+
using Microsoft.TypeSpec.Generator.Providers;
8+
using System;
9+
using System.ClientModel.Primitives;
10+
using System.IO;
11+
using System.Text.Json;
12+
using static Microsoft.TypeSpec.Generator.Snippets.Snippet;
13+
14+
namespace Azure.Generator.Management.Providers
15+
{
16+
internal class ResourceSerializationProvider : TypeProvider
17+
{
18+
private readonly FieldProvider _dataField;
19+
private readonly CSharpType _resourceDataType;
20+
private readonly ResourceClientProvider _resoruce;
21+
private readonly CSharpType _jsonModelInterfaceType;
22+
public ResourceSerializationProvider(ResourceClientProvider resource)
23+
{
24+
_resoruce = resource;
25+
_resourceDataType = resource.ResourceData.Type;
26+
_jsonModelInterfaceType = new CSharpType(typeof(IJsonModel<>), _resourceDataType);
27+
_dataField = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, _jsonModelInterfaceType, "s_dataDeserializationInstance", this);
28+
}
29+
30+
protected override string BuildName() => _resoruce.Name;
31+
32+
protected override string BuildRelativeFilePath()
33+
=> Path.Combine("src", "Generated", $"{Name}.Serialization.cs");
34+
35+
protected override TypeSignatureModifiers BuildDeclarationModifiers()
36+
=> TypeSignatureModifiers.Public | TypeSignatureModifiers.Partial;
37+
38+
protected override CSharpType[] BuildImplements() => [_jsonModelInterfaceType];
39+
40+
protected override FieldProvider[] BuildFields() => [_dataField];
41+
42+
protected override PropertyProvider[] BuildProperties() =>
43+
[
44+
new PropertyProvider(null, MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, _jsonModelInterfaceType, "DataDeserializationInstance", new ExpressionPropertyBody(new AssignmentExpression(_dataField, New.Instance(_resourceDataType), true)), this)
45+
];
46+
47+
protected override MethodProvider[] BuildMethods()
48+
{
49+
var options = new ParameterProvider("options", $"The client options for reading and writing models.", typeof(ModelReaderWriterOptions));
50+
var iModelTInterface = new CSharpType(typeof(IPersistableModel<>), _resourceDataType);
51+
var data = new ParameterProvider("data", $"The binary data to be processed.", typeof(BinaryData));
52+
53+
// void IJsonModel<T>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
54+
var writer = new ParameterProvider("writer", $"The writer to serialize the model to.", typeof(Utf8JsonWriter));
55+
var jsonModelWriteMethod = new MethodProvider(
56+
new MethodSignature(nameof(IJsonModel<object>.Write), null, MethodSignatureModifiers.None, null, null, [writer, options], ExplicitInterface: _jsonModelInterfaceType),
57+
// => ((IJsonModel<T>)Data).Write(writer, options);
58+
new MemberExpression(null, "Data").CastTo(_jsonModelInterfaceType).Invoke(nameof(IJsonModel<object>.Write), writer, options),
59+
this);
60+
61+
// T IJsonModel<T>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
62+
var reader = new ParameterProvider("reader", $"The reader for deserializing the model.", typeof(Utf8JsonReader), isRef: true);
63+
var jsonModelCreatemethod = new MethodProvider(
64+
new MethodSignature(nameof(IJsonModel<object>.Create), null, MethodSignatureModifiers.None, _resourceDataType, null, [reader, options], ExplicitInterface: _jsonModelInterfaceType),
65+
// => DataDeserializationInstance.Create(reader, options);
66+
new MemberExpression(null, "DataDeserializationInstance").Invoke(nameof(IJsonModel<object>.Create), reader, options),
67+
this);
68+
69+
// BinaryData IPersistableModel<T>.Write(ModelReaderWriterOptions options)
70+
var persistableWriteMethod = new MethodProvider(
71+
new MethodSignature(nameof(IPersistableModel<object>.Write), null, MethodSignatureModifiers.None, typeof(BinaryData), null, [options], ExplicitInterface: iModelTInterface),
72+
// => ModelReaderWriter.Write<ResourceData>(Data, options);
73+
Static(typeof(ModelReaderWriter)).Invoke("Write", [new MemberExpression(null, "Data"), options, ModelReaderWriterContextSnippets.Default], [_resourceDataType], false),
74+
this);
75+
76+
// T IPersistableModel<T>.Create(BinaryData data, ModelReaderWriterOptions options)
77+
var persistableCreateMethod = new MethodProvider(
78+
new MethodSignature(nameof(IPersistableModel<object>.Create), null, MethodSignatureModifiers.None, _resourceDataType, null, [data, options], ExplicitInterface: iModelTInterface),
79+
// => ModelReaderWriter.Read<ResourceData>(new BinaryData(reader.ValueSequence));
80+
Static(typeof(ModelReaderWriter)).Invoke("Read", [data, options, ModelReaderWriterContextSnippets.Default], [_resourceDataType], false),
81+
this);
82+
83+
// ModelReaderWriterFormat IPersistableModel<T>.GetFormatFromOptions(ModelReaderWriterOptions options)
84+
var persistableGetFormatMethod = new MethodProvider(
85+
new MethodSignature(nameof(IPersistableModel<object>.GetFormatFromOptions), null, MethodSignatureModifiers.None, typeof(string), null, [options], ExplicitInterface: iModelTInterface),
86+
// => DataDeserializationInstance.GetFormatFromOptions(options);
87+
new MemberExpression(null, "DataDeserializationInstance").Invoke(nameof(IPersistableModel<object>.GetFormatFromOptions), options),
88+
this);
89+
90+
return [jsonModelWriteMethod, jsonModelCreatemethod, persistableWriteMethod, persistableCreateMethod, persistableGetFormatMethod];
91+
}
92+
}
93+
}

eng/packages/http-client-csharp-mgmt/generator/Directory.Build.props

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
<Nullable>enable</Nullable>
44
<ImportDefaultReferences>false</ImportDefaultReferences>
55
<IsShippingLibrary>false</IsShippingLibrary>
6-
<NoWarn>$(NoWarn);CS8002</NoWarn>
6+
<NoWarn>
7+
$(NoWarn);
8+
CS8002;
9+
SCM0005; <!-- Resources currently do not have a parameterless ctor so builders cannot be created for them -->
10+
</NoWarn>
711
</PropertyGroup>
812
<!--
913
Add any shared properties you want for the projects under this package directory that need to be set before the auto imported Directory.Build.props

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FooResource.Serialization.cs

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FoosListAsyncCollectionResult.cs

Lines changed: 93 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/FoosListAsyncCollectionResultOfT.cs

Lines changed: 88 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)