Skip to content

Commit 4052244

Browse files
stevejgordongithub-actions[bot]
authored andcommitted
Fix properties serialization (#6599)
* Implement properties serialization * Add properties serialization tests * Add missing license header
1 parent 2785ccd commit 4052244

9 files changed

+132
-7
lines changed

src/Elastic.Clients.Elasticsearch/Serialization/DefaultRequestResponseSerializer.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ public DefaultRequestResponseSerializer(IElasticsearchClientSettings settings)
4646
new SelfDeserializableConverterFactory(settings),
4747
new SelfTwoWaySerializableConverterFactory(settings),
4848
new IndicesJsonConverter(settings),
49-
new PropertyNameConverter(settings),
5049
new IdsConverter(settings),
5150
new IsADictionaryConverter(),
5251
new ResponseItemConverterFactory(),

src/Elastic.Clients.Elasticsearch/Serialization/DefaultSourceSerializer.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ public DefaultSourceSerializer(IElasticsearchClientSettings settings, JsonSerial
2020
new IdConverter(settings),
2121
new RelationNameConverter(settings),
2222
new RoutingConverter(settings),
23-
new PropertyNameConverter(settings),
2423
new JoinFieldConverter(settings),
2524
new LazyDocumentConverter(settings),
2625
new IdsConverter(settings)

src/Elastic.Clients.Elasticsearch/Serialization/PropertyNameConverter.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
using System;
66
using System.Text.Json;
77
using System.Text.Json.Serialization;
8+
using Elastic.Transport;
89

910
namespace Elastic.Clients.Elasticsearch
1011
{
11-
internal sealed class PropertyNameConverter : JsonConverter<PropertyName?>
12+
internal sealed class PropertyNameConverter : SettingsJsonConverter<PropertyName>
1213
{
13-
private readonly IElasticsearchClientSettings _settings;
14+
public override void WriteAsPropertyName(Utf8JsonWriter writer, PropertyName value, JsonSerializerOptions options) =>
15+
writer.WritePropertyName(((IUrlParameter)value).GetString(GetSettings(options)));
1416

15-
public PropertyNameConverter(IElasticsearchClientSettings settings) => _settings = settings;
17+
public override PropertyName ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
18+
reader.GetString();
1619

1720
public override PropertyName? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1821
{
@@ -33,7 +36,7 @@ public override void Write(Utf8JsonWriter writer, PropertyName? value, JsonSeria
3336
return;
3437
}
3538

36-
var propertyName = _settings.Inferrer.PropertyName(value);
39+
var propertyName = GetSettings(options).Inferrer.PropertyName(value);
3740
writer.WriteStringValue(propertyName);
3841
}
3942
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json;
6+
using System.Text.Json.Serialization;
7+
8+
namespace Elastic.Clients.Elasticsearch
9+
{
10+
/// <summary>
11+
/// Used for derived converters which need access to <see cref="IElasticsearchClientSettings"/> in order to serialize.
12+
/// </summary>
13+
/// <typeparam name="T">The type of object or value handled by the converter.</typeparam>
14+
internal abstract class SettingsJsonConverter<T> : JsonConverter<T>
15+
{
16+
private IElasticsearchClientSettings _settings;
17+
18+
/// <summary>
19+
/// Access the <see cref="IElasticsearchClientSettings"/> for a given <see cref="JsonSerializerOptions"/> instance.
20+
/// </summary>
21+
/// <param name="options">The <see cref="JsonSerializerOptions"/> for which the <see cref="IElasticsearchClientSettings"/> should be retrieved.</param>
22+
/// <returns>An <see cref="IElasticsearchClientSettings"/> instance related to the provided <see cref="JsonSerializerOptions"/>.</returns>
23+
/// <exception cref="JsonException">Thrown if a corresponding <see cref="IElasticsearchClientSettings"/> instance cannot be found for the <see cref="JsonSerializerOptions"/>.</exception>
24+
protected IElasticsearchClientSettings GetSettings(JsonSerializerOptions options)
25+
{
26+
if (_settings is not null)
27+
return _settings;
28+
29+
// We avoid locking here as the result of accessing the settings should be idemopotent and low cost.
30+
31+
if (options.TryGetClientSettings(out var settings))
32+
{
33+
_settings = settings;
34+
return _settings;
35+
}
36+
37+
throw new JsonException("Unable to retrieve ElasticsearchClientSettings settings from JsonSerializerOptions.");
38+
}
39+
}
40+
}

src/Elastic.Clients.Elasticsearch/Types/Mapping/PropertyBase.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,16 @@ internal sealed partial class PropertyInterfaceConverter : JsonConverter<IProper
4040
return DeserializeVariant(type, ref reader, options);
4141
}
4242

43-
public override void Write(Utf8JsonWriter writer, IProperty value, JsonSerializerOptions options) => throw new NotImplementedException();
43+
public override void Write(Utf8JsonWriter writer, IProperty value, JsonSerializerOptions options)
44+
{
45+
if (value is null)
46+
{
47+
writer.WriteNullValue();
48+
return;
49+
}
50+
51+
var type = value.GetType();
52+
53+
JsonSerializer.Serialize(writer, value, type, options);
54+
}
4455
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Threading.Tasks;
6+
using Elastic.Clients.Elasticsearch.Mapping;
7+
using Tests.Domain;
8+
using VerifyXunit;
9+
10+
namespace Tests.Serialization.Mapping;
11+
12+
[UsesVerify]
13+
public class PropertiesSerializationTests : SerializerTestBase
14+
{
15+
[U]
16+
public async Task CanSerialize_Properties_WithPropertyNameExpression()
17+
{
18+
var result = await RoundTripAndVerifyJson(new Properties<Project>
19+
{
20+
{ p => p.Name, new TextProperty { Boost = 1.2 } }
21+
});
22+
23+
var textProperty = result["name"].Should().BeOfType<TextProperty>().Subject;
24+
textProperty.Boost.Should().Be(1.2);
25+
}
26+
27+
[U]
28+
public async Task CanSerialize_MultipleProperties_WithPropertyNameExpression()
29+
{
30+
var result = await RoundTripAndVerifyJson(new Properties<Project>
31+
{
32+
{ p => p.Name, new TextProperty { Boost = 1.2 } },
33+
{ p => p.Description, new TextProperty { Boost = 1.4 } }
34+
});
35+
36+
var nameTextProperty = result["name"].Should().BeOfType<TextProperty>().Subject;
37+
nameTextProperty.Boost.Should().Be(1.2);
38+
39+
var descriptionTextProperty = result["description"].Should().BeOfType<TextProperty>().Subject;
40+
descriptionTextProperty.Boost.Should().Be(1.4);
41+
}
42+
}

tests/Tests/Serialization/SerializerTestBase.cs

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

55
using System.IO;
6+
using System.Text.Json;
67
using System.Threading.Tasks;
78
using Tests.Domain.Extensions;
89
using VerifyXunit;
@@ -129,6 +130,20 @@ static SerializerTestBase()
129130

130131
protected static Inferrer Inferrer => _settings.Inferrer;
131132

133+
public static async Task<string> SerializeAndVerifyJson<T>(T data)
134+
{
135+
var serialisedJson = await SerializeAndGetJsonStringAsync(data);
136+
await Verifier.VerifyJson(serialisedJson);
137+
return serialisedJson;
138+
}
139+
140+
public static async Task<T> RoundTripAndVerifyJson<T>(T data)
141+
{
142+
var serialisedJson = await SerializeAndGetJsonStringAsync(data);
143+
await Verifier.VerifyJson(serialisedJson);
144+
return JsonSerializer.Deserialize<T>(serialisedJson);
145+
}
146+
132147
protected static Stream WrapInStream(string json)
133148
{
134149
var stream = new MemoryStream();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
description: {
3+
boost: 1.4,
4+
type: text
5+
},
6+
name: {
7+
boost: 1.2,
8+
type: text
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
name: {
3+
boost: 1.2,
4+
type: text
5+
}
6+
}

0 commit comments

Comments
 (0)