Skip to content

Commit c5478db

Browse files
authored
Implement IJsonModel of DataFactoryElement<> for AOT compat (Azure#50447)
1 parent 841b308 commit c5478db

10 files changed

+1776
-299
lines changed

sdk/core/Azure.Core.Expressions.DataFactory/api/Azure.Core.Expressions.DataFactory.net8.0.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
namespace Azure.Core.Expressions.DataFactory
22
{
3+
public partial class DataFactoryContext : System.ClientModel.Primitives.ModelReaderWriterContext
4+
{
5+
internal DataFactoryContext() { }
6+
public static Azure.Core.Expressions.DataFactory.DataFactoryContext Default { get { throw null; } }
7+
protected override bool TryGetTypeBuilderCore(System.Type type, out System.ClientModel.Primitives.ModelReaderWriterTypeBuilder builder) { throw null; }
8+
}
39
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
410
public readonly partial struct DataFactoryElementKind : System.IEquatable<Azure.Core.Expressions.DataFactory.DataFactoryElementKind>
511
{
@@ -17,7 +23,7 @@ namespace Azure.Core.Expressions.DataFactory
1723
public static bool operator !=(Azure.Core.Expressions.DataFactory.DataFactoryElementKind left, Azure.Core.Expressions.DataFactory.DataFactoryElementKind right) { throw null; }
1824
public override string ToString() { throw null; }
1925
}
20-
public sealed partial class DataFactoryElement<T>
26+
public sealed partial class DataFactoryElement<T> : System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>, System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>
2127
{
2228
internal DataFactoryElement() { }
2329
public Azure.Core.Expressions.DataFactory.DataFactoryElementKind Kind { get { throw null; } }
@@ -31,6 +37,11 @@ internal DataFactoryElement() { }
3137
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
3238
public override int GetHashCode() { throw null; }
3339
public static implicit operator Azure.Core.Expressions.DataFactory.DataFactoryElement<T> (T literal) { throw null; }
40+
Azure.Core.Expressions.DataFactory.DataFactoryElement<T> System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
41+
void System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
42+
Azure.Core.Expressions.DataFactory.DataFactoryElement<T> System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
43+
string System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
44+
System.BinaryData System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
3445
public override string? ToString() { throw null; }
3546
}
3647
public partial class DataFactoryKeyVaultSecret : Azure.Core.Expressions.DataFactory.DataFactorySecret

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
namespace Azure.Core.Expressions.DataFactory
22
{
3+
public partial class DataFactoryContext : System.ClientModel.Primitives.ModelReaderWriterContext
4+
{
5+
internal DataFactoryContext() { }
6+
public static Azure.Core.Expressions.DataFactory.DataFactoryContext Default { get { throw null; } }
7+
protected override bool TryGetTypeBuilderCore(System.Type type, out System.ClientModel.Primitives.ModelReaderWriterTypeBuilder builder) { throw null; }
8+
}
39
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
410
public readonly partial struct DataFactoryElementKind : System.IEquatable<Azure.Core.Expressions.DataFactory.DataFactoryElementKind>
511
{
@@ -17,7 +23,7 @@ namespace Azure.Core.Expressions.DataFactory
1723
public static bool operator !=(Azure.Core.Expressions.DataFactory.DataFactoryElementKind left, Azure.Core.Expressions.DataFactory.DataFactoryElementKind right) { throw null; }
1824
public override string ToString() { throw null; }
1925
}
20-
public sealed partial class DataFactoryElement<T>
26+
public sealed partial class DataFactoryElement<T> : System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>, System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>
2127
{
2228
internal DataFactoryElement() { }
2329
public Azure.Core.Expressions.DataFactory.DataFactoryElementKind Kind { get { throw null; } }
@@ -31,6 +37,11 @@ internal DataFactoryElement() { }
3137
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
3238
public override int GetHashCode() { throw null; }
3339
public static implicit operator Azure.Core.Expressions.DataFactory.DataFactoryElement<T> (T literal) { throw null; }
40+
Azure.Core.Expressions.DataFactory.DataFactoryElement<T> System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
41+
void System.ClientModel.Primitives.IJsonModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { }
42+
Azure.Core.Expressions.DataFactory.DataFactoryElement<T> System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
43+
string System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
44+
System.BinaryData System.ClientModel.Primitives.IPersistableModel<Azure.Core.Expressions.DataFactory.DataFactoryElement<T>>.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; }
3445
public override string? ToString() { throw null; }
3546
}
3647
public partial class DataFactoryKeyVaultSecret : Azure.Core.Expressions.DataFactory.DataFactorySecret

sdk/core/Azure.Core.Expressions.DataFactory/src/Azure.Core.Expressions.DataFactory.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</PropertyGroup>
1515

1616
<ItemGroup>
17-
<PackageReference Include="Azure.Core" VersionOverride="1.36.0" />
17+
<PackageReference Include="Azure.Core" />
1818
</ItemGroup>
1919

2020
<ItemGroup>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.ClientModel.Primitives;
5+
6+
namespace Azure.Core.Expressions.DataFactory
7+
{
8+
/// <summary>
9+
/// Context class used by <see cref="ModelReaderWriter"/> to read and write models in an AOT compatible way.
10+
/// </summary>
11+
public partial class DataFactoryContext : ModelReaderWriterContext
12+
{
13+
}
14+
}
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.ClientModel.Primitives;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Reflection;
9+
using System.Text.Json;
10+
11+
namespace Azure.Core.Expressions.DataFactory
12+
{
13+
#pragma warning disable SCM0005 // Type must have a parameterless constructor
14+
public sealed partial class DataFactoryElement<T> : IJsonModel<DataFactoryElement<T>>
15+
#pragma warning restore SCM0005 // Type must have a parameterless constructor
16+
{
17+
void IJsonModel<DataFactoryElement<T>>.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options)
18+
{
19+
var format = options.Format == "W" ? ((IPersistableModel<DataFactoryElement<T>>)this).GetFormatFromOptions(options) : options.Format;
20+
if (format != "J")
21+
{
22+
throw new FormatException($"The model {nameof(DataFactoryElement<T>)} does not support '{format}' format.");
23+
}
24+
25+
if (Kind == DataFactoryElementKind.Literal)
26+
{
27+
SerializeLiteral(writer, options);
28+
}
29+
else if (Kind == DataFactoryElementKind.Expression)
30+
{
31+
SerializeExpression(writer, ExpressionString!);
32+
}
33+
else
34+
{
35+
((IUtf8JsonSerializable)Secret!).Write(writer);
36+
}
37+
}
38+
39+
DataFactoryElement<T> IJsonModel<DataFactoryElement<T>>.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options)
40+
{
41+
var format = options.Format == "W" ? ((IPersistableModel<DataFactoryElement<T>>)this).GetFormatFromOptions(options) : options.Format;
42+
if (format != "J")
43+
{
44+
throw new FormatException($"The model {nameof(DataFactoryElement<T>)} does not support '{format}' format.");
45+
}
46+
47+
using var document = JsonDocument.ParseValue(ref reader);
48+
return Create(document.RootElement, options);
49+
}
50+
51+
BinaryData IPersistableModel<DataFactoryElement<T>>.Write(ModelReaderWriterOptions options)
52+
{
53+
var format = options.Format == "W" ? ((IPersistableModel<DataFactoryElement<T>>)this).GetFormatFromOptions(options) : options.Format;
54+
if (format != "J")
55+
{
56+
throw new FormatException($"The model {nameof(DataFactoryElement<T>)} does not support '{format}' format.");
57+
}
58+
59+
return ModelReaderWriter.Write(this, options, DataFactoryContext.Default);
60+
}
61+
62+
DataFactoryElement<T> IPersistableModel<DataFactoryElement<T>>.Create(BinaryData data, ModelReaderWriterOptions options)
63+
{
64+
var format = options.Format == "W" ? ((IPersistableModel<DataFactoryElement<T>>)this).GetFormatFromOptions(options) : options.Format;
65+
if (format != "J")
66+
{
67+
throw new FormatException($"The model {nameof(DataFactoryElement<T>)} does not support '{format}' format.");
68+
}
69+
70+
using var document = JsonDocument.Parse(data);
71+
return Create(document.RootElement, options);
72+
}
73+
74+
string IPersistableModel<DataFactoryElement<T>>.GetFormatFromOptions(ModelReaderWriterOptions options) => "J";
75+
76+
internal static DataFactoryElement<T> Create(JsonElement element, ModelReaderWriterOptions options)
77+
{
78+
if (element.ValueKind == JsonValueKind.Null)
79+
{
80+
return null!;
81+
}
82+
83+
// Check for Expression or Secret (non-literal) elements
84+
if (TryGetNonLiteral(element, out DataFactoryElement<T?>? nonLiteralElement))
85+
{
86+
return nonLiteralElement!;
87+
}
88+
89+
// Handle literal values based on type T
90+
return CreateLiteralElement(element);
91+
}
92+
93+
private void SerializeLiteral(Utf8JsonWriter writer, ModelReaderWriterOptions options)
94+
{
95+
switch (Literal)
96+
{
97+
case TimeSpan timeSpan:
98+
writer.WriteStringValue(timeSpan, "c");
99+
break;
100+
case Uri uri:
101+
writer.WriteStringValue(uri.AbsoluteUri);
102+
break;
103+
case IList<string> stringList:
104+
writer.WriteStartArray();
105+
foreach (string? item in stringList)
106+
{
107+
writer.WriteStringValue(item);
108+
}
109+
writer.WriteEndArray();
110+
break;
111+
case IDictionary<string, string?> dictionary:
112+
writer.WriteStartObject();
113+
foreach (KeyValuePair<string, string?> pair in dictionary)
114+
{
115+
writer.WritePropertyName(pair.Key);
116+
writer.WriteStringValue(pair.Value);
117+
}
118+
writer.WriteEndObject();
119+
break;
120+
case IDictionary<string, BinaryData?> binaryDictionary:
121+
writer.WriteStartObject();
122+
foreach (KeyValuePair<string, BinaryData?> pair in binaryDictionary)
123+
{
124+
writer.WritePropertyName(pair.Key);
125+
if (pair.Value != null)
126+
{
127+
using JsonDocument document = JsonDocument.Parse(pair.Value.ToString());
128+
document.RootElement.WriteTo(writer);
129+
}
130+
else
131+
{
132+
writer.WriteNullValue();
133+
}
134+
}
135+
writer.WriteEndObject();
136+
break;
137+
case BinaryData binaryData:
138+
using (JsonDocument document = JsonDocument.Parse(binaryData.ToString()))
139+
{
140+
document.RootElement.WriteTo(writer);
141+
}
142+
break;
143+
default:
144+
WriteObjectValue(writer, Literal!, options);
145+
break;
146+
}
147+
}
148+
149+
private void WriteObjectValue<T1>(Utf8JsonWriter writer, T1 value, ModelReaderWriterOptions options)
150+
{
151+
switch (value)
152+
{
153+
case IJsonModel<T1> jsonModel:
154+
jsonModel.Write(writer, options);
155+
break;
156+
case IEnumerable<KeyValuePair<string, object>> enumerable:
157+
writer.WriteStartObject();
158+
foreach (KeyValuePair<string, object> pair in enumerable)
159+
{
160+
writer.WritePropertyName(pair.Key);
161+
WriteObjectValue(writer, pair.Value, options);
162+
}
163+
writer.WriteEndObject();
164+
break;
165+
case IEnumerable<object> objectEnumerable:
166+
writer.WriteStartArray();
167+
foreach (object item in objectEnumerable)
168+
{
169+
WriteObjectValue(writer, item, options);
170+
}
171+
writer.WriteEndArray();
172+
break;
173+
case null:
174+
case IUtf8JsonSerializable:
175+
case byte[]:
176+
case BinaryData:
177+
case JsonElement:
178+
case int:
179+
case decimal:
180+
case double:
181+
case float:
182+
case long:
183+
case string:
184+
case bool:
185+
case Guid:
186+
case DateTimeOffset:
187+
case DateTime:
188+
case TimeSpan:
189+
writer.WriteObjectValue(value!);
190+
break;
191+
192+
default:
193+
throw new NotSupportedException("Not supported type " + value.GetType());
194+
}
195+
}
196+
197+
private static void SerializeExpression(Utf8JsonWriter writer, string value)
198+
{
199+
writer.WriteStartObject();
200+
writer.WritePropertyName("type");
201+
writer.WriteStringValue("Expression");
202+
writer.WritePropertyName("value");
203+
writer.WriteStringValue(value);
204+
writer.WriteEndObject();
205+
}
206+
207+
private static bool TryGetNonLiteral(JsonElement json, out DataFactoryElement<T?>? element)
208+
{
209+
element = null;
210+
if (json.ValueKind == JsonValueKind.Object && json.TryGetProperty("type", out JsonElement typeValue))
211+
{
212+
if (typeValue.ValueEquals("Expression"))
213+
{
214+
if (json.EnumerateObject().Count() != 2)
215+
{
216+
// Expression should only have two properties: type and value
217+
return false;
218+
}
219+
var expressionValue = json.GetProperty("value").GetString();
220+
element = new DataFactoryElement<T?>(expressionValue, DataFactoryElementKind.Expression);
221+
}
222+
else
223+
{
224+
element = DataFactoryElement<T>.FromSecretBase(DataFactorySecret.DeserializeDataFactorySecretBaseDefinition(json)!);
225+
}
226+
}
227+
228+
return element != null;
229+
}
230+
231+
private static DataFactoryElement<T> CreateLiteralElement(JsonElement json)
232+
{
233+
T? value = default;
234+
235+
// Handle specific type conversions
236+
if (typeof(T) == typeof(IDictionary<string, string>) && json.ValueKind == JsonValueKind.Object)
237+
{
238+
var dictionary = new Dictionary<string, string>();
239+
foreach (var item in json.EnumerateObject())
240+
{
241+
dictionary.Add(item.Name, item.Value.GetString()!);
242+
}
243+
return new DataFactoryElement<T>((T)(object)dictionary);
244+
}
245+
246+
if (typeof(T) == typeof(IDictionary<string, BinaryData>) && json.ValueKind == JsonValueKind.Object)
247+
{
248+
var dictionary = new Dictionary<string, BinaryData>();
249+
foreach (var item in json.EnumerateObject())
250+
{
251+
dictionary.Add(item.Name, BinaryData.FromString(item.Value.GetRawText()));
252+
}
253+
return new DataFactoryElement<T>((T)(object)dictionary);
254+
}
255+
256+
if (typeof(T) == typeof(DateTimeOffset) || typeof(T) == typeof(DateTimeOffset?))
257+
{
258+
return new DataFactoryElement<T>((T)(object)json.GetDateTimeOffset("O"));
259+
}
260+
261+
if (typeof(T) == typeof(TimeSpan) || typeof(T) == typeof(TimeSpan?))
262+
{
263+
return new DataFactoryElement<T>((T)(object)json.GetTimeSpan("c"));
264+
}
265+
266+
if (typeof(T) == typeof(Uri))
267+
{
268+
return new DataFactoryElement<T>((T)(object)new Uri(json.GetString()!));
269+
}
270+
271+
if (typeof(T) == typeof(BinaryData))
272+
{
273+
return new DataFactoryElement<T>((T)(object)BinaryData.FromString(json.GetRawText()!));
274+
}
275+
276+
if (typeof(T).IsGenericType)
277+
{
278+
var methodInfo = GetGenericSerializationMethod(typeof(T).GenericTypeArguments[0]!, nameof(DataFactoryElementJsonConverter.DeserializeGenericList));
279+
return (DataFactoryElement<T>)methodInfo!.Invoke(null, new object[] { json })!;
280+
}
281+
282+
// Handle primitive and other types
283+
var obj = json.GetObject();
284+
if (obj is not null)
285+
value = (T)obj;
286+
287+
return new DataFactoryElement<T>(value);
288+
}
289+
290+
private static MethodInfo GetGenericSerializationMethod(Type typeToConvert, string methodName)
291+
{
292+
return typeof(DataFactoryElementJsonConverter)
293+
.GetMethod(
294+
methodName,
295+
BindingFlags.Static | BindingFlags.NonPublic)!
296+
.MakeGenericMethod(typeToConvert);
297+
}
298+
}
299+
}

0 commit comments

Comments
 (0)