From a7420d2e13b3b2432b25e09711145094816af047 Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Mon, 17 Oct 2022 16:39:43 +0100 Subject: [PATCH 1/2] Fix dictionary key serialization for Name type --- .../Serialization/EnumStructConverter.cs | 37 ++++++++++++++++ .../Serialization/StringAliasConverter.cs | 32 +++----------- .../_Generated/Api/SearchResponse.g.cs | 4 +- .../CreateIndexSerializationTests.cs | 43 +++++++++++++++++++ .../IndexSettingsSerializationTests.cs | 20 ++++----- ...thAliases_SerializesCorrectly.verified.txt | 15 +++++++ 6 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs create mode 100644 tests/Tests/IndexManagement/CreateIndexSerializationTests.cs create mode 100644 tests/Tests/_VerifySnapshots/CreateIndexSerializationTests.CreateIndexWithAliases_SerializesCorrectly.verified.txt diff --git a/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs b/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs new file mode 100644 index 00000000000..d4b9967ec0a --- /dev/null +++ b/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs @@ -0,0 +1,37 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using System; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Elastic.Clients.Elasticsearch.Serialization; + +internal sealed class EnumStructConverter : JsonConverter where T : new() +{ + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var value = reader.GetString(); + + var instance = (T)Activator.CreateInstance( + typeof(T), + BindingFlags.Instance | BindingFlags.NonPublic, + args: new object[] { value }, // TODO: Perf - Review use of ArrayPool + binder: null, + culture: null)!; + + return instance; + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + var enumValue = value.ToString(); + + if (!string.IsNullOrEmpty(enumValue)) + writer.WriteStringValue(value.ToString()); + else + writer.WriteNullValue(); + } +} diff --git a/src/Elastic.Clients.Elasticsearch/Serialization/StringAliasConverter.cs b/src/Elastic.Clients.Elasticsearch/Serialization/StringAliasConverter.cs index ce1c71a5b5f..a1107687c1a 100644 --- a/src/Elastic.Clients.Elasticsearch/Serialization/StringAliasConverter.cs +++ b/src/Elastic.Clients.Elasticsearch/Serialization/StringAliasConverter.cs @@ -9,8 +9,13 @@ namespace Elastic.Clients.Elasticsearch.Serialization; +// TODO - In .NET 7 we could review supporting IParsable as a type constraint? internal sealed class StringAliasConverter : JsonConverter { + public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Read(ref reader, typeToConvert, options); + + public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => writer.WritePropertyName(value.ToString()); + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); @@ -37,30 +42,3 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions } } } - -internal sealed class EnumStructConverter : JsonConverter where T : new() -{ - public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var value = reader.GetString(); - - var instance = (T)Activator.CreateInstance( - typeof(T), - BindingFlags.Instance | BindingFlags.NonPublic, - args: new object[] { value }, // TODO: Perf - Review use of ArrayPool - binder: null, - culture: null)!; - - return instance; - } - - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) - { - var enumValue = value.ToString(); - - if (!string.IsNullOrEmpty(enumValue)) - writer.WriteStringValue(value.ToString()); - else - writer.WriteNullValue(); - } -} diff --git a/src/Elastic.Clients.Elasticsearch/_Generated/Api/SearchResponse.g.cs b/src/Elastic.Clients.Elasticsearch/_Generated/Api/SearchResponse.g.cs index 98e1ee7eb5a..5f5fc2a11f2 100644 --- a/src/Elastic.Clients.Elasticsearch/_Generated/Api/SearchResponse.g.cs +++ b/src/Elastic.Clients.Elasticsearch/_Generated/Api/SearchResponse.g.cs @@ -23,7 +23,7 @@ #nullable restore namespace Elastic.Clients.Elasticsearch; -public sealed partial class SearchResponse : ElasticsearchResponseBase +public partial class SearchResponse : ElasticsearchResponseBase { [JsonInclude] [JsonPropertyName("aggregations")] @@ -76,4 +76,4 @@ public sealed partial class SearchResponse : ElasticsearchResponseBas [JsonInclude] [JsonPropertyName("took")] public long Took { get; init; } -} \ No newline at end of file +} diff --git a/tests/Tests/IndexManagement/CreateIndexSerializationTests.cs b/tests/Tests/IndexManagement/CreateIndexSerializationTests.cs new file mode 100644 index 00000000000..5f93cd4b120 --- /dev/null +++ b/tests/Tests/IndexManagement/CreateIndexSerializationTests.cs @@ -0,0 +1,43 @@ +// Licensed to Elasticsearch B.V under one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Elastic.Clients.Elasticsearch.IndexManagement; +using Elastic.Clients.Elasticsearch.QueryDsl; +using System.Threading.Tasks; +using Tests.Serialization; +using VerifyXunit; + +namespace Tests.IndexManagement; + +[UsesVerify] +public class CreateIndexSerializationTests : SerializerTestBase +{ + [U] + public async Task CreateIndexWithAliases_SerializesCorrectly() + { + var alias1 = new Alias(); + var alias2 = new Alias { Filter = QueryContainer.Term(new TermQuery("username") { Value = "stevegordon" }), Routing = "shard-1" }; + + var descriptor = new CreateRequestDescriptor("test") + .Aliases(aliases => aliases + .Add("alias_1", alias1) + .Add("alias_2", alias2)); + + var json = await SerializeAndGetJsonStringAsync(descriptor); + + await Verifier.VerifyJson(json); + + var createRequest = new CreateRequest("test") + { + Aliases = new() + { + { "alias_1", alias1 }, + { "alias_2", alias2 } + } + }; + + var objectJson = await SerializeAndGetJsonStringAsync(createRequest); + objectJson.Should().Be(json); + } +} diff --git a/tests/Tests/IndexManagement/IndexSettingsSerializationTests.cs b/tests/Tests/IndexManagement/IndexSettingsSerializationTests.cs index c70c33cd841..4b11c56d9ef 100644 --- a/tests/Tests/IndexManagement/IndexSettingsSerializationTests.cs +++ b/tests/Tests/IndexManagement/IndexSettingsSerializationTests.cs @@ -25,17 +25,17 @@ public async Task CanSerializerIndexSettingsWithCustomAnalyzer() // Resolved after improved code-generation of internally-tagged untions to include // converters for the variant interfaces. - var descriptor = new IndexSettingsDescriptor(); - descriptor.Analysis(a => a - .Analyzer(a => a - .Custom("whitespace_lowercase", wl => wl - .Tokenizer("whitespace") - .Filter(Enumerable.Repeat("lowercase", 1)) - ) - ) + var descriptor = new IndexSettingsDescriptor() + .Analysis(a => a + .Analyzer(a => a + .Custom("whitespace_lowercase", wl => wl + .Tokenizer("whitespace") + .Filter(Enumerable.Repeat("lowercase", 1)) + ) + ) ); - var json = SerializeAndGetJsonString(descriptor); + var json = await SerializeAndGetJsonStringAsync(descriptor); await Verifier.VerifyJson(json); var indexSettings = DeserializeJsonString(json); @@ -44,7 +44,7 @@ public async Task CanSerializerIndexSettingsWithCustomAnalyzer() customAnalyzer.Tokenizer.Should().Be("whitespace"); customAnalyzer.Filter.Should().ContainSingle("lowercase"); - var objectJson = SerializeAndGetJsonString(indexSettings); + var objectJson = await SerializeAndGetJsonStringAsync(indexSettings); objectJson.Should().Be(json); } diff --git a/tests/Tests/_VerifySnapshots/CreateIndexSerializationTests.CreateIndexWithAliases_SerializesCorrectly.verified.txt b/tests/Tests/_VerifySnapshots/CreateIndexSerializationTests.CreateIndexWithAliases_SerializesCorrectly.verified.txt new file mode 100644 index 00000000000..5e314ded1a7 --- /dev/null +++ b/tests/Tests/_VerifySnapshots/CreateIndexSerializationTests.CreateIndexWithAliases_SerializesCorrectly.verified.txt @@ -0,0 +1,15 @@ +{ + aliases: { + alias_1: {}, + alias_2: { + filter: { + term: { + username: { + value: stevegordon + } + } + }, + routing: shard-1 + } + } +} \ No newline at end of file From acd53f186fde0d2e898374654b3cd5f23034b07a Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Mon, 17 Oct 2022 16:41:26 +0100 Subject: [PATCH 2/2] Fix BOM --- .../Serialization/EnumStructConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs b/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs index d4b9967ec0a..b7f8643de00 100644 --- a/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs +++ b/src/Elastic.Clients.Elasticsearch/Serialization/EnumStructConverter.cs @@ -1,4 +1,4 @@ -// Licensed to Elasticsearch B.V under one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information.