From bd71ff8f27585dc1477ed9bed6f47673190b2ac5 Mon Sep 17 00:00:00 2001 From: Russ Cam Date: Thu, 29 Jun 2017 13:09:20 +1000 Subject: [PATCH] Use serializer when deserializing LazyDocument to T (#2791) * Use serializer when deserializing LazyDocument to T When converting a LazyDocument to type T, use the JsonNetSerializer configured, along with all registered contract resolvers. Fixes #2788 * Direct cast * Add non-generic overload for As() Relates #2408 (cherry picked from commit 109bcb039916365c9f0c84237090a33e7a6b95eb) --- .../LazyDocument/LazyDocument.cs | 27 ++++-- .../LazyDocument/LazyDocumentJsonConverter.cs | 17 ++-- .../Search/Search/Hits/InnerHitsResult.cs | 12 +-- src/Tests/Reproduce/GithubIssue2788.cs | 90 +++++++++++++++++++ 4 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 src/Tests/Reproduce/GithubIssue2788.cs diff --git a/src/Nest/CommonAbstractions/LazyDocument/LazyDocument.cs b/src/Nest/CommonAbstractions/LazyDocument/LazyDocument.cs index f3fd2ee30ed..4331309e047 100644 --- a/src/Nest/CommonAbstractions/LazyDocument/LazyDocument.cs +++ b/src/Nest/CommonAbstractions/LazyDocument/LazyDocument.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Nest @@ -7,21 +8,37 @@ namespace Nest public interface ILazyDocument { /// - /// + /// Creates an instance of from this + /// instance /// - /// - /// + /// The type T As() where T : class; + + /// + /// Creates an instance of from this + /// instance + /// + /// The type + object As(Type objectType); } public class LazyDocument : ILazyDocument { internal JToken _Value { get; set; } + internal JsonSerializer _Serializer { get; set; } + /// public T As() where T : class { var jToken = this._Value; - return jToken?.ToObject(); + return jToken?.ToObject(_Serializer); + } + + /// + public object As(Type objectType) + { + var jToken = this._Value; + return jToken?.ToObject(objectType, _Serializer); } } } diff --git a/src/Nest/CommonAbstractions/LazyDocument/LazyDocumentJsonConverter.cs b/src/Nest/CommonAbstractions/LazyDocument/LazyDocumentJsonConverter.cs index 2072e370c99..45ea427b5fa 100644 --- a/src/Nest/CommonAbstractions/LazyDocument/LazyDocumentJsonConverter.cs +++ b/src/Nest/CommonAbstractions/LazyDocument/LazyDocumentJsonConverter.cs @@ -8,21 +8,26 @@ internal class LazyDocumentJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - var d = value as LazyDocument; + var d = (LazyDocument)value; if (d?._Value == null) + { + writer.WriteNull(); return; + } + writer.WriteToken(d._Value.CreateReader()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var document = serializer.Deserialize(reader) as JToken; - return new LazyDocument { _Value = document }; + return new LazyDocument + { + _Value = document, + _Serializer = serializer + }; } - public override bool CanConvert(Type objectType) - { - return true; - } + public override bool CanConvert(Type objectType) => true; } } diff --git a/src/Nest/Search/Search/Hits/InnerHitsResult.cs b/src/Nest/Search/Search/Hits/InnerHitsResult.cs index 129c4891b6e..bc76e7d0dd9 100644 --- a/src/Nest/Search/Search/Hits/InnerHitsResult.cs +++ b/src/Nest/Search/Search/Hits/InnerHitsResult.cs @@ -6,13 +6,15 @@ namespace Nest { public class InnerHitsResult { - [JsonProperty("hits")] public InnerHitsMetaData Hits { get; internal set; } - public IEnumerable Documents() where T : class - { - return this.Hits == null ? Enumerable.Empty() : this.Hits.Documents(); - } + /// + /// Retrieve documents as a strongly typed + /// collection + /// + /// The hits document type + public IEnumerable Documents() where T : class => + this.Hits == null ? Enumerable.Empty() : this.Hits.Documents(); } } \ No newline at end of file diff --git a/src/Tests/Reproduce/GithubIssue2788.cs b/src/Tests/Reproduce/GithubIssue2788.cs new file mode 100644 index 00000000000..231d05d4531 --- /dev/null +++ b/src/Tests/Reproduce/GithubIssue2788.cs @@ -0,0 +1,90 @@ +using System; +using System.Linq; +using Elasticsearch.Net; +using FluentAssertions; +using FluentAssertions.Common; +using Nest; +using Tests.Framework; +using Tests.Framework.ManagedElasticsearch.Clusters; +using Xunit; + +namespace Tests.Reproduce +{ + public class GithubIssue2788 : IClusterFixture + { + private readonly WritableCluster _cluster; + + public GithubIssue2788(WritableCluster cluster) + { + _cluster = cluster; + } + + // sample mapping with nested objects with TimeSpan field + class Root + { + [Nested] + public Child[] Children { get; set; } + } + + class Child + { + public TimeSpan StartTime { get; set; } + + public TimeSpan EndTime { get; set; } + } + + [I] + public void CanDeserializeNumberToTimeSpanInInnerHits() + { + var indexName = "sample"; + var client = _cluster.Client; + + //create index with automapping + client.CreateIndex(indexName, create => create + .Mappings(mappings => mappings + .Map(map => map + .AutoMap() + ) + ) + ); + + var startTime = new TimeSpan(1, 2, 3); + var endTime = new TimeSpan(2, 3, 4); + + client.Index(new Root + { + Children = new[] + { + new Child + { + StartTime = startTime, + EndTime = endTime + + } + } + }, index => index + .Index(indexName) + .Refresh(Refresh.WaitFor) + ); + + var result = client.Search(search => search + .Query(query => query + .Nested(nested => nested + .Query(nestedQuery => nestedQuery + .MatchAll() + ) + .Path(i => i.Children) + .InnerHits() + ) + ) + .Index(indexName) + ); + + var child = result.Hits.First().InnerHits.Single().Value.Documents().Single(); + + child.Should().NotBeNull(); + child.StartTime.Should().Be(startTime); + child.EndTime.Should().Be(endTime); + } + } +} \ No newline at end of file