Skip to content

Commit 5197a92

Browse files
[9.1] Fix deserialization of Context (#8688) (#8690)
Co-authored-by: Florian Bernd <[email protected]>
1 parent ad4808a commit 5197a92

File tree

3 files changed

+112
-25
lines changed

3 files changed

+112
-25
lines changed

src/Elastic.Clients.Elasticsearch/_Generated/Types/Core/Context.Converters.g.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public sealed partial class ContextConverter : System.Text.Json.Serialization.Js
2727
{
2828
public override Elastic.Clients.Elasticsearch.Core.Search.Context Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
2929
{
30-
var selector = static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.ByPropertyOfT1(ref r, o, "dummy");
30+
var selector = static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.Match(ref r, o, static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.MatchTokenTypes(ref r, o, Elastic.Clients.Elasticsearch.Serialization.JsonTokenTypes.StartObject | Elastic.Clients.Elasticsearch.Serialization.JsonTokenTypes.StartArray, static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.T2(ref r, o)), static (ref System.Text.Json.Utf8JsonReader r, System.Text.Json.JsonSerializerOptions o) => JsonUnionSelector.T1(ref r, o));
3131
return selector(ref reader, options) switch
3232
{
3333
Elastic.Clients.Elasticsearch.UnionTag.T1 => new Elastic.Clients.Elasticsearch.Core.Search.Context(reader.ReadValue<string>(options, null)),

src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonReaderExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,9 @@ public static KeyValuePair<TKey, TValue> ReadKeyValuePairValue<TKey, TValue>(thi
474474
public static List<T>? ReadSingleOrManyCollectionValue<T>(this ref Utf8JsonReader reader, JsonSerializerOptions options,
475475
JsonReadFunc<T>? readElement)
476476
{
477+
// TODO: Allow passing a selector function to distinguish between single or many in complex scenarios
478+
// (e.g. when the single element can be an array, see: GeoLocation).
479+
477480
if (reader.TokenType is JsonTokenType.Null)
478481
{
479482
return null;

src/Elastic.Clients.Elasticsearch/_Shared/Next/JsonUnionSelector.cs

Lines changed: 108 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6-
using System.Collections.Generic;
76
using System.Text.Json;
87

98
namespace Elastic.Clients.Elasticsearch.Serialization;
@@ -38,61 +37,146 @@ internal enum JsonTokenTypes
3837

3938
internal static class JsonUnionSelector
4039
{
41-
public static UnionTag ByTokenType(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes first, JsonTokenTypes second)
40+
/// <summary>
41+
/// A selector function that always returns <see cref="UnionTag.None"/>.
42+
/// </summary>
43+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
44+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
45+
/// <returns>A static value of <see cref="UnionTag.None"/>.</returns>
46+
public static UnionTag None(ref Utf8JsonReader reader, JsonSerializerOptions options)
47+
{
48+
_ = reader;
49+
_ = options;
50+
return UnionTag.None;
51+
}
52+
53+
/// <summary>
54+
/// A selector function that always returns <see cref="UnionTag.T1"/>.
55+
/// </summary>
56+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
57+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
58+
/// <returns>A static value of <see cref="UnionTag.T1"/>.</returns>
59+
public static UnionTag T1(ref Utf8JsonReader reader, JsonSerializerOptions options)
4260
{
4361
_ = reader;
4462
_ = options;
63+
return UnionTag.T1;
64+
}
4565

46-
if (((int)first & (1 << (int)reader.TokenType)) is not 0)
66+
/// <summary>
67+
/// A selector function that always returns <see cref="UnionTag.T2"/>.
68+
/// </summary>
69+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
70+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
71+
/// <returns>A static value of <see cref="UnionTag.T2"/>.</returns>
72+
public static UnionTag T2(ref Utf8JsonReader reader, JsonSerializerOptions options)
73+
{
74+
_ = reader;
75+
_ = options;
76+
return UnionTag.T2;
77+
}
78+
79+
// We avoid using a `params` array for performance reasons. Create `Match()` overloads with additional parameters as needed.
80+
public static UnionTag Match(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonUnionSelectorFunc case1, JsonUnionSelectorFunc case2)
81+
{
82+
if (case1(ref reader, options) is var tag1 and not UnionTag.None)
4783
{
48-
return UnionTag.T1;
84+
return tag1;
4985
}
5086

51-
if (((int)second & (1 << (int)reader.TokenType)) is not 0)
87+
if (case2(ref reader, options) is var tag2 and not UnionTag.None)
5288
{
53-
return UnionTag.T2;
89+
return tag2;
5490
}
5591

5692
return UnionTag.None;
5793
}
5894

59-
public static UnionTag ByPropertyOfT1(ref Utf8JsonReader reader, JsonSerializerOptions options, string name)
95+
public static UnionTag MatchTokenTypes(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes types, JsonUnionSelectorFunc next)
6096
{
61-
reader.ValidateToken(JsonTokenType.StartObject);
62-
63-
var internalReader = reader;
64-
65-
while (internalReader.Read() && (internalReader.TokenType is JsonTokenType.PropertyName))
97+
if (((int)types & (1 << (int)reader.TokenType)) is not 0)
6698
{
67-
if (internalReader.ValueTextEquals(name))
68-
{
69-
return UnionTag.T1;
70-
}
71-
72-
internalReader.Read();
73-
internalReader.Skip();
99+
return next(ref reader, options);
74100
}
75101

76-
return UnionTag.T2;
102+
return UnionTag.None;
77103
}
78104

79-
public static UnionTag ByPropertyOfT2(ref Utf8JsonReader reader, JsonSerializerOptions options, string name)
105+
public static UnionTag MatchProperty(ref Utf8JsonReader reader, JsonSerializerOptions options, string name, UnionTag result)
80106
{
81-
reader.ValidateToken(JsonTokenType.StartObject);
107+
if (reader.TokenType is not JsonTokenType.StartObject)
108+
{
109+
return UnionTag.None;
110+
}
82111

83112
var internalReader = reader;
84113

85114
while (internalReader.Read() && (internalReader.TokenType is JsonTokenType.PropertyName))
86115
{
87116
if (internalReader.ValueTextEquals(name))
88117
{
89-
return UnionTag.T2;
118+
return result;
90119
}
91120

92121
internalReader.Read();
93122
internalReader.Skip();
94123
}
95124

96-
return UnionTag.T1;
125+
return UnionTag.None;
126+
}
127+
128+
/// <summary>
129+
/// A selector function that selects a union variant based on the current JSON token type.
130+
/// </summary>
131+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
132+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
133+
/// <param name="first">The JSON token types that resolve to <see cref="UnionTag.T1"/>.</param>
134+
/// <param name="second">The JSON token types that resolve to <see cref="UnionTag.T2"/>.</param>
135+
/// <returns>
136+
/// Either <see cref="UnionTag.T1"/> or <see cref="UnionTag.T2"/> if the current token type of <paramref name="reader"/> matches one
137+
/// of the provided JSON token types or <see cref="UnionTag.None"/>, if not.
138+
/// </returns>
139+
public static UnionTag ByTokenType(ref Utf8JsonReader reader, JsonSerializerOptions options, JsonTokenTypes first, JsonTokenTypes second)
140+
{
141+
return Match(ref reader, options,
142+
(ref r, o) => MatchTokenTypes(ref r, o, first, T1),
143+
(ref r, o) => MatchTokenTypes(ref r, o, second, T2)
144+
);
145+
}
146+
147+
/// <summary>
148+
/// A selector function that selects a union variant based on the current JSON token type.
149+
/// </summary>
150+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
151+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
152+
/// <param name="name">The property name to look for.</param>
153+
/// <returns>
154+
/// <see cref="UnionTag.T1"/> if the <paramref name="reader"/> points to an object that contains a property of the given
155+
/// <paramref name="name"/> or <see cref="UnionTag.T2"/>, if not.
156+
/// </returns>
157+
public static UnionTag ByPropertyOfT1(ref Utf8JsonReader reader, JsonSerializerOptions options, string name)
158+
{
159+
return Match(ref reader, options,
160+
(ref r, o) => MatchProperty(ref r, o, name, UnionTag.T1),
161+
T2
162+
);
163+
}
164+
165+
/// <summary>
166+
/// A selector function that selects a union variant based on the current JSON token type.
167+
/// </summary>
168+
/// <param name="reader">A reference to the <see cref="Utf8JsonReader"/> instance.</param>
169+
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use.</param>
170+
/// <param name="name">The property name to look for.</param>
171+
/// <returns>
172+
/// <see cref="UnionTag.T2"/> if the <paramref name="reader"/> points to an object that contains a property of the given
173+
/// <paramref name="name"/> or <see cref="UnionTag.T1"/>, if not.
174+
/// </returns>
175+
public static UnionTag ByPropertyOfT2(ref Utf8JsonReader reader, JsonSerializerOptions options, string name)
176+
{
177+
return Match(ref reader, options,
178+
(ref r, o) => MatchProperty(ref r, o, name, UnionTag.T2),
179+
T1
180+
);
97181
}
98182
}

0 commit comments

Comments
 (0)