From 7f76dc6325fb2087d06e464203662987826a65ea Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sat, 6 Oct 2018 13:10:06 +0200 Subject: [PATCH 01/11] Added Tests for Query with inner query --- .../Linq/query_with_inner_query.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/Marten.Testing/Linq/query_with_inner_query.cs diff --git a/src/Marten.Testing/Linq/query_with_inner_query.cs b/src/Marten.Testing/Linq/query_with_inner_query.cs new file mode 100644 index 0000000000..279dcc71f1 --- /dev/null +++ b/src/Marten.Testing/Linq/query_with_inner_query.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Xunit; + +namespace Marten.Testing.Linq +{ + [ControlledQueryStoryteller] + public class query_with_inner_query : IntegratedFixture + { + public class TypeWithInnerCollections + { + public Guid Id { get; set; } + public string[] Array { get; set; } + public IEnumerable Enumerable { get; set; } + public IEnumerable IEnumerableFromArray { get; set; } + public IEnumerable IEnumerbaleFromList { get; set; } + public List List { get; set; } + public IList IList { get; set; } + public IReadOnlyCollection IReadonlyCollection { get; set; } + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } + + public static TypeWithInnerCollections Create(params string[] array) + { + return new TypeWithInnerCollections() + { + Id = Guid.NewGuid(), + Array = array, + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + List = array.ToList(), + IList = array.ToList(), + IReadonlyCollection = array.ToList() + }; + } + } + + private static readonly TypeWithInnerCollections[] TestData = new TypeWithInnerCollections[] + { + TypeWithInnerCollections.Create("one", "two"), + TypeWithInnerCollections.Create("two", "three"), + TypeWithInnerCollections.Create("four", "five"), + }; + + private const string SearchPhrase = "two"; + + public static readonly TheoryData>> Predicates = new TheoryData>> + { + x => x.Array.Contains(SearchPhrase), + x => x.Enumerable.Contains(SearchPhrase), + x => x.IEnumerableFromArray.Contains(SearchPhrase), + x => x.IEnumerbaleFromList.Contains(SearchPhrase), + x => x.List.Contains(SearchPhrase), + x => x.IList.Contains(SearchPhrase), + x => x.IReadonlyCollection.Contains(SearchPhrase), + x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any() + }; + + public query_with_inner_query() + { + using (var session = theStore.OpenSession()) + { + session.Store(TestData); + session.SaveChanges(); + } + } + + [Theory] + [MemberData(nameof(Predicates))] + public async Task can_query_against_array_of_string(Expression> predicate) + + { + StoreOptions(options => options.UseDefaultSerialization()); + + using (var query = theStore.QuerySession()) + { + var results = await query.Query() + .Where(predicate) + .ToListAsync(); + + results.All(e => e.Enumerable.Contains(SearchPhrase)).ShouldBeTrue(); + } + } + } +} \ No newline at end of file From 5f8975627dddc35a833b331e1c970483e4f68ef7 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sat, 6 Oct 2018 13:14:59 +0200 Subject: [PATCH 02/11] Removed redundant space --- src/Marten.Testing/Linq/query_with_inner_query.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Marten.Testing/Linq/query_with_inner_query.cs b/src/Marten.Testing/Linq/query_with_inner_query.cs index 279dcc71f1..2920e442dd 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query.cs @@ -71,7 +71,6 @@ public query_with_inner_query() [Theory] [MemberData(nameof(Predicates))] public async Task can_query_against_array_of_string(Expression> predicate) - { StoreOptions(options => options.UseDefaultSerialization()); From e868ce4e9d3a9774dd458c89a8cffa6e8af062d4 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Mon, 8 Oct 2018 10:06:56 +0200 Subject: [PATCH 03/11] Updated tests to not have false positive results --- .../Linq/query_with_inner_query.cs | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/Marten.Testing/Linq/query_with_inner_query.cs b/src/Marten.Testing/Linq/query_with_inner_query.cs index 2920e442dd..7eef30ac3a 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query.cs @@ -3,6 +3,8 @@ using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; +using Marten.Services; +using Shouldly; using Xunit; namespace Marten.Testing.Linq @@ -13,6 +15,7 @@ public class query_with_inner_query : IntegratedFixture public class TypeWithInnerCollections { public Guid Id { get; set; } + public string Flatten { get; set; } public string[] Array { get; set; } public IEnumerable Enumerable { get; set; } public IEnumerable IEnumerableFromArray { get; set; } @@ -28,12 +31,28 @@ public static TypeWithInnerCollections Create(params string[] array) { Id = Guid.NewGuid(), Array = array, + Flatten = array.Aggregate((i, j) => i + j), Enumerable = array.AsEnumerable(), IEnumerableFromArray = array, IEnumerbaleFromList = array.ToList(), List = array.ToList(), IList = array.ToList(), - IReadonlyCollection = array.ToList() + IReadonlyCollection = array.ToList(), + IReadonlyCollectionOfInnerClasses = new List + { + new TypeWithInnerCollections() + { + Id = Guid.NewGuid(), + Array = array, + Flatten = array.Aggregate((i, j) => i + j), + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + List = array.ToList(), + IList = array.ToList(), + IReadonlyCollection = array.ToList(), + } + } }; } } @@ -56,23 +75,16 @@ public static TypeWithInnerCollections Create(params string[] array) x => x.List.Contains(SearchPhrase), x => x.IList.Contains(SearchPhrase), x => x.IReadonlyCollection.Contains(SearchPhrase), - x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any() + x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any(), + x => x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "onetwo").Any() || x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "twothree").Any() }; - public query_with_inner_query() - { - using (var session = theStore.OpenSession()) - { - session.Store(TestData); - session.SaveChanges(); - } - } - [Theory] [MemberData(nameof(Predicates))] public async Task can_query_against_array_of_string(Expression> predicate) - { - StoreOptions(options => options.UseDefaultSerialization()); + { + ConfigureStoreToHaveJsonTypeNameHandlingNone(); + SetupTestData(); using (var query = theStore.QuerySession()) { @@ -80,8 +92,28 @@ public async Task can_query_against_array_of_string(Expression e.Enumerable.Contains(SearchPhrase)).ShouldBeTrue(); } } + + private void ConfigureStoreToHaveJsonTypeNameHandlingNone() + { + var serializer = new JsonNetSerializer(); + serializer.Customize(s => + { + s.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None; + }); + StoreOptions(options => options.Serializer(serializer)); + } + + private void SetupTestData() + { + using (var session = theStore.OpenSession()) + { + session.Store(TestData); + session.SaveChanges(); + } + } } } \ No newline at end of file From f52d6338cf16761804bb519abe71dd7be41e1757 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Fri, 9 Nov 2018 17:28:15 +0100 Subject: [PATCH 04/11] Added test for attribute type name handling --- ...ry_with_attribute_typenamehandling_none.cs | 111 ++++++++++++++++++ ...uery_with_global_typenamehandling_none.cs} | 2 +- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs rename src/Marten.Testing/Linq/{query_with_inner_query.cs => query_with_inner_query_with_global_typenamehandling_none.cs} (96%) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs new file mode 100644 index 0000000000..cb206d993f --- /dev/null +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Shouldly; +using Xunit; + +namespace Marten.Testing.Linq +{ + [ControlledQueryStoryteller] + public class query_with_inner_query_with_attribute_typenamehandling_none : IntegratedFixture + { + public class TypeWithInnerCollections + { + public Guid Id { get; set; } + public string Flatten { get; set; } + public string[] Array { get; set; } + + [JsonProperty(ItemTypeNameHandling = TypeNameHandling.None)] + public IEnumerable Enumerable { get; set; } + + public IEnumerable IEnumerableFromArray { get; set; } + public IEnumerable IEnumerbaleFromList { get; set; } + public List List { get; set; } + public IList IList { get; set; } + public IReadOnlyCollection IReadonlyCollection { get; set; } + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } + + public static TypeWithInnerCollections Create(params string[] array) + { + return new TypeWithInnerCollections() + { + Id = Guid.NewGuid(), + Array = array, + Flatten = array.Aggregate((i, j) => i + j), + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + List = array.ToList(), + IList = array.ToList(), + IReadonlyCollection = array.ToList(), + IReadonlyCollectionOfInnerClasses = new List + { + new TypeWithInnerCollections() + { + Id = Guid.NewGuid(), + Array = array, + Flatten = array.Aggregate((i, j) => i + j), + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + List = array.ToList(), + IList = array.ToList(), + IReadonlyCollection = array.ToList(), + } + } + }; + } + } + + private static readonly TypeWithInnerCollections[] TestData = new TypeWithInnerCollections[] + { + TypeWithInnerCollections.Create("one", "two"), + TypeWithInnerCollections.Create("two", "three"), + TypeWithInnerCollections.Create("four", "five"), + }; + + private const string SearchPhrase = "two"; + + public static readonly TheoryData>> Predicates = new TheoryData>> + { + x => x.Array.Contains(SearchPhrase), + x => x.Enumerable.Contains(SearchPhrase), + x => x.IEnumerableFromArray.Contains(SearchPhrase), + x => x.IEnumerbaleFromList.Contains(SearchPhrase), + x => x.List.Contains(SearchPhrase), + x => x.IList.Contains(SearchPhrase), + x => x.IReadonlyCollection.Contains(SearchPhrase), + x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any(), + x => x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "onetwo").Any() || x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "twothree").Any() + }; + + [Theory] + [MemberData(nameof(Predicates))] + public async Task can_query_against_array_of_string(Expression> predicate) + { + SetupTestData(); + + using (var query = theStore.QuerySession()) + { + var results = await query.Query() + .Where(predicate) + .ToListAsync(); + + results.Count.ShouldBe(2); + results.All(e => e.Enumerable.Contains(SearchPhrase)).ShouldBeTrue(); + } + } + + private void SetupTestData() + { + using (var session = theStore.OpenSession()) + { + session.Store(TestData); + session.SaveChanges(); + } + } + } +} \ No newline at end of file diff --git a/src/Marten.Testing/Linq/query_with_inner_query.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs similarity index 96% rename from src/Marten.Testing/Linq/query_with_inner_query.cs rename to src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs index 7eef30ac3a..ead765b6ea 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs @@ -10,7 +10,7 @@ namespace Marten.Testing.Linq { [ControlledQueryStoryteller] - public class query_with_inner_query : IntegratedFixture + public class query_with_inner_query_with_global_typenamehandling_none : IntegratedFixture { public class TypeWithInnerCollections { From e5ae49180751c948f3e89ad26620310bf0662794 Mon Sep 17 00:00:00 2001 From: mysticmind Date: Sat, 27 Apr 2019 21:55:08 +0530 Subject: [PATCH 05/11] Add collection to array Newtonsoft.Json based JSON converter --- .../Util/CollectionToArrayJsonConverter.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Marten/Util/CollectionToArrayJsonConverter.cs diff --git a/src/Marten/Util/CollectionToArrayJsonConverter.cs b/src/Marten/Util/CollectionToArrayJsonConverter.cs new file mode 100644 index 0000000000..c58e9cfc23 --- /dev/null +++ b/src/Marten/Util/CollectionToArrayJsonConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; + +namespace Marten.Util +{ + /// + /// Serialize collection type property to JSON array using a custom Newtonsoft.Json JsonConverter + /// Note that without using custom `JsonConverter`, `Newtonsoft.Json` stores it as $type and $value. + /// Or you may need to resort to `Newtonsoft.Json.TypeNameHandling.None` which has its own side-effects + /// + /// Type of the collection + public class CollectionToArrayJsonConverter : JsonConverter + { + private readonly List _types = new List + { + typeof(ICollection), + typeof(IReadOnlyCollection), + typeof(IEnumerable), + typeof(T[]) + }; + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var o = value as IEnumerable; + serializer.Serialize(writer, o?.ToArray()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return serializer.Deserialize>(reader); + } + + public override bool CanConvert(Type objectType) + { + return _types.Contains(objectType); + } + } +} \ No newline at end of file From 4bc194d6a4b13645d9c24c68b8d899d2f1feafbc Mon Sep 17 00:00:00 2001 From: mysticmind Date: Sat, 27 Apr 2019 21:56:31 +0530 Subject: [PATCH 06/11] Update unit test document class to use JsonConverter attribute --- ...query_with_global_typenamehandling_none.cs | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs index ead765b6ea..133fbeffd3 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_global_typenamehandling_none.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Marten.Services; +using Newtonsoft.Json; using Shouldly; using Xunit; @@ -17,12 +18,19 @@ public class TypeWithInnerCollections public Guid Id { get; set; } public string Flatten { get; set; } public string[] Array { get; set; } + public List List { get; set; } + public IList IList { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable Enumerable { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable IEnumerableFromArray { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable IEnumerbaleFromList { get; set; } - public List List { get; set; } - public IList IList { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public ICollection ICollection { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IReadOnlyCollection IReadonlyCollection { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } public static TypeWithInnerCollections Create(params string[] array) @@ -30,26 +38,28 @@ public static TypeWithInnerCollections Create(params string[] array) return new TypeWithInnerCollections() { Id = Guid.NewGuid(), - Array = array, Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), Enumerable = array.AsEnumerable(), IEnumerableFromArray = array, IEnumerbaleFromList = array.ToList(), - List = array.ToList(), - IList = array.ToList(), + ICollection = array.ToList(), IReadonlyCollection = array.ToList(), IReadonlyCollectionOfInnerClasses = new List { new TypeWithInnerCollections() { Id = Guid.NewGuid(), - Array = array, Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), Enumerable = array.AsEnumerable(), IEnumerableFromArray = array, + ICollection = array.ToList(), IEnumerbaleFromList = array.ToList(), - List = array.ToList(), - IList = array.ToList(), IReadonlyCollection = array.ToList(), } } @@ -74,22 +84,22 @@ public static TypeWithInnerCollections Create(params string[] array) x => x.IEnumerbaleFromList.Contains(SearchPhrase), x => x.List.Contains(SearchPhrase), x => x.IList.Contains(SearchPhrase), + x => x.ICollection.Contains(SearchPhrase), x => x.IReadonlyCollection.Contains(SearchPhrase), x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any(), x => x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "onetwo").Any() || x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "twothree").Any() }; - [Theory] + [Theory] [MemberData(nameof(Predicates))] public async Task can_query_against_array_of_string(Expression> predicate) { - ConfigureStoreToHaveJsonTypeNameHandlingNone(); - SetupTestData(); - - using (var query = theStore.QuerySession()) - { - var results = await query.Query() - .Where(predicate) + SetupTestData(); + + using (var query = theStore.QuerySession()) + { + var results = await query.Query() + .Where(predicate) .ToListAsync(); results.Count.ShouldBe(2); @@ -97,22 +107,12 @@ public async Task can_query_against_array_of_string(Expression - { - s.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None; - }); - StoreOptions(options => options.Serializer(serializer)); - } - private void SetupTestData() { - using (var session = theStore.OpenSession()) - { - session.Store(TestData); - session.SaveChanges(); + using (var session = theStore.OpenSession()) + { + session.Store(TestData); + session.SaveChanges(); } } } From 4009bcd58a0796300206f63c2f146381ef200176 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sun, 28 Apr 2019 12:17:30 +0200 Subject: [PATCH 07/11] Refactored CollectionToArrayJsonConverter to not need generic parameter, added JsonNetContractResolver to allow global setting of storing collections as arrays --- .../Acceptance/noda_time_acceptance.cs | 2 + ...ry_with_attribute_typenamehandling_none.cs | 83 +++++++++++-------- ...ith_global_CollectionStorage_WithArray.cs} | 22 ++--- src/Marten/ISerializer.cs | 10 ++- .../Services/Json/JsonNetContractResolver.cs | 49 +++++++++++ src/Marten/Services/JsonNetSerializer.cs | 53 +++++++----- src/Marten/StoreOptions.cs | 5 +- .../Util/CollectionToArrayJsonConverter.cs | 30 ++++--- 8 files changed, 171 insertions(+), 83 deletions(-) rename src/Marten.Testing/Linq/{query_with_inner_query_with_global_typenamehandling_none.cs => query_with_inner_query_with_global_CollectionStorage_WithArray.cs} (82%) create mode 100644 src/Marten/Services/Json/JsonNetContractResolver.cs diff --git a/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs b/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs index 1e61d8a00a..271e6394d3 100644 --- a/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs +++ b/src/Marten.NodaTime.Testing/Acceptance/noda_time_acceptance.cs @@ -161,6 +161,8 @@ private class CustomJsonSerializer : ISerializer public Casing Casing => throw new NotImplementedException(); + public CollectionStorage CollectionStorage => throw new NotImplementedException(); + public T FromJson(TextReader reader) { throw new NotImplementedException(); diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs index cb206d993f..ad0b4ec864 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs @@ -10,66 +10,78 @@ namespace Marten.Testing.Linq { [ControlledQueryStoryteller] - public class query_with_inner_query_with_attribute_typenamehandling_none : IntegratedFixture + public class query_with_inner_query : IntegratedFixture { - public class TypeWithInnerCollections + public class TypeWithInnerCollectionsWithJsonConverterAttribute { public Guid Id { get; set; } public string Flatten { get; set; } public string[] Array { get; set; } + public List List { get; set; } + public IList IList { get; set; } - [JsonProperty(ItemTypeNameHandling = TypeNameHandling.None)] + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable Enumerable { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable IEnumerableFromArray { get; set; } + + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IEnumerable IEnumerbaleFromList { get; set; } - public List List { get; set; } - public IList IList { get; set; } + + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public ICollection ICollection { get; set; } + + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] public IReadOnlyCollection IReadonlyCollection { get; set; } - public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } - public static TypeWithInnerCollections Create(params string[] array) + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } + + public static TypeWithInnerCollectionsWithJsonConverterAttribute Create(params string[] array) { - return new TypeWithInnerCollections() + return new TypeWithInnerCollectionsWithJsonConverterAttribute() { Id = Guid.NewGuid(), - Array = array, Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), Enumerable = array.AsEnumerable(), IEnumerableFromArray = array, IEnumerbaleFromList = array.ToList(), - List = array.ToList(), - IList = array.ToList(), + ICollection = array.ToList(), IReadonlyCollection = array.ToList(), - IReadonlyCollectionOfInnerClasses = new List + IReadonlyCollectionOfInnerClasses = new List { - new TypeWithInnerCollections() + new TypeWithInnerCollectionsWithJsonConverterAttribute() { Id = Guid.NewGuid(), - Array = array, Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), Enumerable = array.AsEnumerable(), IEnumerableFromArray = array, + ICollection = array.ToList(), IEnumerbaleFromList = array.ToList(), - List = array.ToList(), - IList = array.ToList(), IReadonlyCollection = array.ToList(), } } }; } - } + }; - private static readonly TypeWithInnerCollections[] TestData = new TypeWithInnerCollections[] + private static readonly TypeWithInnerCollectionsWithJsonConverterAttribute[] TestData = new TypeWithInnerCollectionsWithJsonConverterAttribute[] { - TypeWithInnerCollections.Create("one", "two"), - TypeWithInnerCollections.Create("two", "three"), - TypeWithInnerCollections.Create("four", "five"), + TypeWithInnerCollectionsWithJsonConverterAttribute.Create("one", "two"), + TypeWithInnerCollectionsWithJsonConverterAttribute.Create("two", "three"), + TypeWithInnerCollectionsWithJsonConverterAttribute.Create("four", "five"), }; private const string SearchPhrase = "two"; - public static readonly TheoryData>> Predicates = new TheoryData>> + public static readonly TheoryData>> Predicates = new TheoryData>> { x => x.Array.Contains(SearchPhrase), x => x.Enumerable.Contains(SearchPhrase), @@ -77,21 +89,22 @@ public static TypeWithInnerCollections Create(params string[] array) x => x.IEnumerbaleFromList.Contains(SearchPhrase), x => x.List.Contains(SearchPhrase), x => x.IList.Contains(SearchPhrase), + x => x.ICollection.Contains(SearchPhrase), x => x.IReadonlyCollection.Contains(SearchPhrase), x => x.IReadonlyCollection.Where(e => e == SearchPhrase).Any(), x => x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "onetwo").Any() || x.IReadonlyCollectionOfInnerClasses.Where(e => e.Flatten == "twothree").Any() }; - [Theory] + [Theory] [MemberData(nameof(Predicates))] - public async Task can_query_against_array_of_string(Expression> predicate) - { - SetupTestData(); - - using (var query = theStore.QuerySession()) - { - var results = await query.Query() - .Where(predicate) + public async Task having_type_with_CollectionToArrayJsonConverter_can_query_against_array_of_string(Expression> predicate) + { + SetupTestData(); + + using (var query = theStore.QuerySession()) + { + var results = await query.Query() + .Where(predicate) .ToListAsync(); results.Count.ShouldBe(2); @@ -101,10 +114,10 @@ public async Task can_query_against_array_of_string(Expression List { get; set; } public IList IList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable Enumerable { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable IEnumerableFromArray { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable IEnumerbaleFromList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public ICollection ICollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IReadOnlyCollection IReadonlyCollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } public static TypeWithInnerCollections Create(params string[] array) @@ -92,8 +90,12 @@ public static TypeWithInnerCollections Create(params string[] array) [Theory] [MemberData(nameof(Predicates))] - public async Task can_query_against_array_of_string(Expression> predicate) + public async Task having_store_options_with_CollectionStorage_AsArray_can_query_against_array_of_string(Expression> predicate) { + StoreOptions(options => + { + options.UseDefaultSerialization(collectionStorage: CollectionStorage.AsArray); + }); SetupTestData(); using (var query = theStore.QuerySession()) diff --git a/src/Marten/ISerializer.cs b/src/Marten/ISerializer.cs index 19fb0a50a2..65c89e58a4 100644 --- a/src/Marten/ISerializer.cs +++ b/src/Marten/ISerializer.cs @@ -20,7 +20,6 @@ public interface ISerializer /// string ToJson(object document); - /// /// Deserialize a JSON string into an object of type T /// @@ -52,7 +51,10 @@ public interface ISerializer EnumStorage EnumStorage { get; } Casing Casing { get; } + + CollectionStorage CollectionStorage { get; } } + // ENDSAMPLE public enum EnumStorage @@ -67,4 +69,10 @@ public enum Casing CamelCase, SnakeCase } + + public enum CollectionStorage + { + Default, + AsArray + } } \ No newline at end of file diff --git a/src/Marten/Services/Json/JsonNetContractResolver.cs b/src/Marten/Services/Json/JsonNetContractResolver.cs new file mode 100644 index 0000000000..8ff406a04f --- /dev/null +++ b/src/Marten/Services/Json/JsonNetContractResolver.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using Marten.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Marten.Services.Json +{ + public class JsonNetContractResolver : DefaultContractResolver + { + public Casing Casing { get; } + + public CollectionStorage CollectionStorage { get; } + + public JsonNetContractResolver() + { + } + + public JsonNetContractResolver(Casing casing, CollectionStorage collectionStorage) + { + Casing = casing; + CollectionStorage = collectionStorage; + + SetNamingStrategy(casing); + } + + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + if (CollectionStorage == CollectionStorage.AsArray && CollectionToArrayJsonConverter.Instance.CanConvert(property.PropertyType)) + { + property.Converter = CollectionToArrayJsonConverter.Instance; + } + return property; + } + + private void SetNamingStrategy(Casing casing) + { + if (casing == Casing.CamelCase) + { + NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; + } + else if (casing == Casing.SnakeCase) + { + NamingStrategy = new SnakeCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true }; + }; + } + } +} \ No newline at end of file diff --git a/src/Marten/Services/JsonNetSerializer.cs b/src/Marten/Services/JsonNetSerializer.cs index 9b1f4d2c92..51874c671c 100644 --- a/src/Marten/Services/JsonNetSerializer.cs +++ b/src/Marten/Services/JsonNetSerializer.cs @@ -1,9 +1,9 @@ using System; using System.IO; using Baseline; +using Marten.Services.Json; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; namespace Marten.Services { @@ -11,8 +11,9 @@ public class JsonNetSerializer : ISerializer { private readonly JsonSerializer _clean = new JsonSerializer { - TypeNameHandling = TypeNameHandling.None, - DateFormatHandling = DateFormatHandling.IsoDateFormat + TypeNameHandling = TypeNameHandling.None, + DateFormatHandling = DateFormatHandling.IsoDateFormat, + ContractResolver = new JsonNetContractResolver() }; // SAMPLE: newtonsoft-configuration @@ -22,12 +23,14 @@ public class JsonNetSerializer : ISerializer // ISO 8601 formatting of DateTime's is mandatory DateFormatHandling = DateFormatHandling.IsoDateFormat, - MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead + MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead, + ContractResolver = new JsonNetContractResolver() }; + // ENDSAMPLE /// - /// Customize the inner Newtonsoft formatter. + /// Customize the inner Newtonsoft formatter. /// /// public void Customize(Action configure) @@ -77,7 +80,8 @@ public string ToCleanJson(object document) private EnumStorage _enumStorage = EnumStorage.AsInteger; private Casing _casing = Casing.Default; - + private CollectionStorage _collectionStorage = CollectionStorage.Default; + /// /// Specify whether .Net Enum values should be stored as integers or strings /// within the Json document. Default is AsInteger. @@ -119,22 +123,27 @@ public Casing Casing { _casing = value; - if (value == Casing.Default) - { - _serializer.ContractResolver = new DefaultContractResolver(); - _clean.ContractResolver = new DefaultContractResolver(); - } - else if (value == Casing.CamelCase) - { - _serializer.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() }; - _clean.ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true } }; - } - else - { - _serializer.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() }; - _clean.ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy { ProcessDictionaryKeys = true, OverrideSpecifiedNames = true } }; - } + _serializer.ContractResolver = new JsonNetContractResolver(_casing, CollectionStorage); + _clean.ContractResolver = new JsonNetContractResolver(_casing, CollectionStorage); + } + } + + /// + /// Specify whether properties in the JSON document should use Camel or Pascal casing. + /// + public CollectionStorage CollectionStorage + { + get + { + return _collectionStorage; + } + set + { + _collectionStorage = value; + + _serializer.ContractResolver = new JsonNetContractResolver(Casing, _collectionStorage); + _clean.ContractResolver = new JsonNetContractResolver(Casing, _collectionStorage); } } - } + } } \ No newline at end of file diff --git a/src/Marten/StoreOptions.cs b/src/Marten/StoreOptions.cs index 284a50edfa..1b9c58cdc2 100644 --- a/src/Marten/StoreOptions.cs +++ b/src/Marten/StoreOptions.cs @@ -218,9 +218,10 @@ public void Serializer(ISerializer serializer) /// /// /// Casing style to be used in serialization - public void UseDefaultSerialization(EnumStorage enumStyle = EnumStorage.AsInteger, Casing casing = Casing.Default) + /// Allow to set collection storage as raw arrays (without explicit types) + public void UseDefaultSerialization(EnumStorage enumStyle = EnumStorage.AsInteger, Casing casing = Casing.Default, CollectionStorage collectionStorage = CollectionStorage.Default) { - Serializer(new JsonNetSerializer { EnumStorage = enumStyle, Casing = casing }); + Serializer(new JsonNetSerializer { EnumStorage = enumStyle, Casing = casing, CollectionStorage = collectionStorage }); } /// diff --git a/src/Marten/Util/CollectionToArrayJsonConverter.cs b/src/Marten/Util/CollectionToArrayJsonConverter.cs index c58e9cfc23..f78bdd10a0 100644 --- a/src/Marten/Util/CollectionToArrayJsonConverter.cs +++ b/src/Marten/Util/CollectionToArrayJsonConverter.cs @@ -8,33 +8,37 @@ namespace Marten.Util /// /// Serialize collection type property to JSON array using a custom Newtonsoft.Json JsonConverter /// Note that without using custom `JsonConverter`, `Newtonsoft.Json` stores it as $type and $value. - /// Or you may need to resort to `Newtonsoft.Json.TypeNameHandling.None` which has its own side-effects + /// Or you may need to resort to `Newtonsoft.Json.TypeNameHandling.None` which has its own side-effects /// /// Type of the collection - public class CollectionToArrayJsonConverter : JsonConverter - { - private readonly List _types = new List + public class CollectionToArrayJsonConverter : JsonConverter + { + public static CollectionToArrayJsonConverter Instance = new CollectionToArrayJsonConverter(); + + private readonly static List _types = new List { - typeof(ICollection), - typeof(IReadOnlyCollection), - typeof(IEnumerable), - typeof(T[]) - }; - + typeof(ICollection<>), + typeof(IList<>), + typeof(IReadOnlyCollection<>), + typeof(IEnumerable<>) + }; + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - var o = value as IEnumerable; + var o = value as IEnumerable; serializer.Serialize(writer, o?.ToArray()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - return serializer.Deserialize>(reader); + return serializer.Deserialize(reader, objectType); } public override bool CanConvert(Type objectType) { - return _types.Contains(objectType); + return _types.Contains(objectType) + || objectType.IsArray + || (objectType.IsGenericType && _types.Contains(objectType.GetGenericTypeDefinition())); } } } \ No newline at end of file From c23a584942bd9b3550895f4f11e3b77d4e18190d Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sun, 28 Apr 2019 12:22:35 +0200 Subject: [PATCH 08/11] Rename test filename to be more descriptive --- ...inner_query_with_CollectionToArrayJsonConverter_onProperty.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Marten.Testing/Linq/{query_with_inner_query_with_attribute_typenamehandling_none.cs => query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs} (100%) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs similarity index 100% rename from src/Marten.Testing/Linq/query_with_inner_query_with_attribute_typenamehandling_none.cs rename to src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs From 970efd76ca0163151458ecc748c4509ef6031aad Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sun, 28 Apr 2019 12:23:18 +0200 Subject: [PATCH 09/11] Rename test class name to be more descriptive --- ...nner_query_with_CollectionToArrayJsonConverter_onProperty.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs index ad0b4ec864..a8e1a60d5a 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs @@ -10,7 +10,7 @@ namespace Marten.Testing.Linq { [ControlledQueryStoryteller] - public class query_with_inner_query : IntegratedFixture + public class query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty : IntegratedFixture { public class TypeWithInnerCollectionsWithJsonConverterAttribute { From b074f9443109b9a307d5d2bb355a420e77ae513b Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sun, 28 Apr 2019 12:54:20 +0200 Subject: [PATCH 10/11] Fixed failing tests --- ...llectionToArrayJsonConverter_onProperty.cs | 76 +++++++++---------- ...with_global_CollectionStorage_WithArray.cs | 62 +++++++-------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs index a8e1a60d5a..18f5790b64 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs @@ -9,50 +9,47 @@ namespace Marten.Testing.Linq { - [ControlledQueryStoryteller] - public class query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty : IntegratedFixture + public class TypeWithInnerCollectionsWithJsonConverterAttribute { - public class TypeWithInnerCollectionsWithJsonConverterAttribute - { - public Guid Id { get; set; } - public string Flatten { get; set; } - public string[] Array { get; set; } - public List List { get; set; } - public IList IList { get; set; } + public Guid Id { get; set; } + public string Flatten { get; set; } + public string[] Array { get; set; } + public List List { get; set; } + public IList IList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public IEnumerable Enumerable { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable Enumerable { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public IEnumerable IEnumerableFromArray { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable IEnumerableFromArray { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public IEnumerable IEnumerbaleFromList { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IEnumerable IEnumerbaleFromList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public ICollection ICollection { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public ICollection ICollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public IReadOnlyCollection IReadonlyCollection { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IReadOnlyCollection IReadonlyCollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] - public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } + [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } - public static TypeWithInnerCollectionsWithJsonConverterAttribute Create(params string[] array) + public static TypeWithInnerCollectionsWithJsonConverterAttribute Create(params string[] array) + { + return new TypeWithInnerCollectionsWithJsonConverterAttribute() { - return new TypeWithInnerCollectionsWithJsonConverterAttribute() - { - Id = Guid.NewGuid(), - Flatten = array.Aggregate((i, j) => i + j), - Array = array, - List = array.ToList(), - IList = array.ToList(), - Enumerable = array.AsEnumerable(), - IEnumerableFromArray = array, - IEnumerbaleFromList = array.ToList(), - ICollection = array.ToList(), - IReadonlyCollection = array.ToList(), - IReadonlyCollectionOfInnerClasses = new List + Id = Guid.NewGuid(), + Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + ICollection = array.ToList(), + IReadonlyCollection = array.ToList(), + IReadonlyCollectionOfInnerClasses = new List { new TypeWithInnerCollectionsWithJsonConverterAttribute() { @@ -68,10 +65,13 @@ public static TypeWithInnerCollectionsWithJsonConverterAttribute Create(params s IReadonlyCollection = array.ToList(), } } - }; - } - }; + }; + } + }; + [ControlledQueryStoryteller] + public class query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty : IntegratedFixture + { private static readonly TypeWithInnerCollectionsWithJsonConverterAttribute[] TestData = new TypeWithInnerCollectionsWithJsonConverterAttribute[] { TypeWithInnerCollectionsWithJsonConverterAttribute.Create("one", "two"), diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_global_CollectionStorage_WithArray.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_global_CollectionStorage_WithArray.cs index 566f874f91..0cc3de80d1 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_global_CollectionStorage_WithArray.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_global_CollectionStorage_WithArray.cs @@ -8,44 +8,41 @@ namespace Marten.Testing.Linq { - [ControlledQueryStoryteller] - public class query_with_inner_query_with_global_CollectionStorage_WithArray : IntegratedFixture + public class TypeWithInnerCollections { - public class TypeWithInnerCollections - { - public Guid Id { get; set; } - public string Flatten { get; set; } - public string[] Array { get; set; } - public List List { get; set; } - public IList IList { get; set; } + public Guid Id { get; set; } + public string Flatten { get; set; } + public string[] Array { get; set; } + public List List { get; set; } + public IList IList { get; set; } - public IEnumerable Enumerable { get; set; } + public IEnumerable Enumerable { get; set; } - public IEnumerable IEnumerableFromArray { get; set; } + public IEnumerable IEnumerableFromArray { get; set; } - public IEnumerable IEnumerbaleFromList { get; set; } + public IEnumerable IEnumerbaleFromList { get; set; } - public ICollection ICollection { get; set; } + public ICollection ICollection { get; set; } - public IReadOnlyCollection IReadonlyCollection { get; set; } + public IReadOnlyCollection IReadonlyCollection { get; set; } - public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } + public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } - public static TypeWithInnerCollections Create(params string[] array) + public static TypeWithInnerCollections Create(params string[] array) + { + return new TypeWithInnerCollections() { - return new TypeWithInnerCollections() - { - Id = Guid.NewGuid(), - Flatten = array.Aggregate((i, j) => i + j), - Array = array, - List = array.ToList(), - IList = array.ToList(), - Enumerable = array.AsEnumerable(), - IEnumerableFromArray = array, - IEnumerbaleFromList = array.ToList(), - ICollection = array.ToList(), - IReadonlyCollection = array.ToList(), - IReadonlyCollectionOfInnerClasses = new List + Id = Guid.NewGuid(), + Flatten = array.Aggregate((i, j) => i + j), + Array = array, + List = array.ToList(), + IList = array.ToList(), + Enumerable = array.AsEnumerable(), + IEnumerableFromArray = array, + IEnumerbaleFromList = array.ToList(), + ICollection = array.ToList(), + IReadonlyCollection = array.ToList(), + IReadonlyCollectionOfInnerClasses = new List { new TypeWithInnerCollections() { @@ -61,10 +58,13 @@ public static TypeWithInnerCollections Create(params string[] array) IReadonlyCollection = array.ToList(), } } - }; - } + }; } + } + [ControlledQueryStoryteller] + public class query_with_inner_query_with_global_CollectionStorage_WithArray : IntegratedFixture + { private static readonly TypeWithInnerCollections[] TestData = new TypeWithInnerCollections[] { TypeWithInnerCollections.Create("one", "two"), From 58481ed79af6591a19156eeff4be63e3a15f9ecc Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sun, 28 Apr 2019 14:27:21 +0200 Subject: [PATCH 11/11] Applied PR comments --- ...ith_CollectionToArrayJsonConverter_onProperty.cs | 13 +++++++------ .../Json/JsonNetCollectionToArrayJsonConverter.cs} | 7 +++---- src/Marten/Services/Json/JsonNetContractResolver.cs | 4 ++-- src/Marten/Services/JsonNetSerializer.cs | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/Marten/{Util/CollectionToArrayJsonConverter.cs => Services/Json/JsonNetCollectionToArrayJsonConverter.cs} (84%) diff --git a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs index 18f5790b64..79ea5e257d 100644 --- a/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs +++ b/src/Marten.Testing/Linq/query_with_inner_query_with_CollectionToArrayJsonConverter_onProperty.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; +using Marten.Services.Json; using Newtonsoft.Json; using Shouldly; using Xunit; @@ -17,22 +18,22 @@ public class TypeWithInnerCollectionsWithJsonConverterAttribute public List List { get; set; } public IList IList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public IEnumerable Enumerable { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public IEnumerable IEnumerableFromArray { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public IEnumerable IEnumerbaleFromList { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public ICollection ICollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public IReadOnlyCollection IReadonlyCollection { get; set; } - [JsonConverter(typeof(Marten.Util.CollectionToArrayJsonConverter))] + [JsonConverter(typeof(JsonNetCollectionToArrayJsonConverter))] public IReadOnlyCollection IReadonlyCollectionOfInnerClasses { get; set; } public static TypeWithInnerCollectionsWithJsonConverterAttribute Create(params string[] array) diff --git a/src/Marten/Util/CollectionToArrayJsonConverter.cs b/src/Marten/Services/Json/JsonNetCollectionToArrayJsonConverter.cs similarity index 84% rename from src/Marten/Util/CollectionToArrayJsonConverter.cs rename to src/Marten/Services/Json/JsonNetCollectionToArrayJsonConverter.cs index f78bdd10a0..0bbe6bae46 100644 --- a/src/Marten/Util/CollectionToArrayJsonConverter.cs +++ b/src/Marten/Services/Json/JsonNetCollectionToArrayJsonConverter.cs @@ -3,17 +3,16 @@ using System.Linq; using Newtonsoft.Json; -namespace Marten.Util +namespace Marten.Services.Json { /// /// Serialize collection type property to JSON array using a custom Newtonsoft.Json JsonConverter /// Note that without using custom `JsonConverter`, `Newtonsoft.Json` stores it as $type and $value. /// Or you may need to resort to `Newtonsoft.Json.TypeNameHandling.None` which has its own side-effects /// - /// Type of the collection - public class CollectionToArrayJsonConverter : JsonConverter + public class JsonNetCollectionToArrayJsonConverter : JsonConverter { - public static CollectionToArrayJsonConverter Instance = new CollectionToArrayJsonConverter(); + public static JsonNetCollectionToArrayJsonConverter Instance = new JsonNetCollectionToArrayJsonConverter(); private readonly static List _types = new List { diff --git a/src/Marten/Services/Json/JsonNetContractResolver.cs b/src/Marten/Services/Json/JsonNetContractResolver.cs index 8ff406a04f..ea02b23211 100644 --- a/src/Marten/Services/Json/JsonNetContractResolver.cs +++ b/src/Marten/Services/Json/JsonNetContractResolver.cs @@ -27,9 +27,9 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ { var property = base.CreateProperty(member, memberSerialization); - if (CollectionStorage == CollectionStorage.AsArray && CollectionToArrayJsonConverter.Instance.CanConvert(property.PropertyType)) + if (CollectionStorage == CollectionStorage.AsArray && JsonNetCollectionToArrayJsonConverter.Instance.CanConvert(property.PropertyType)) { - property.Converter = CollectionToArrayJsonConverter.Instance; + property.Converter = JsonNetCollectionToArrayJsonConverter.Instance; } return property; } diff --git a/src/Marten/Services/JsonNetSerializer.cs b/src/Marten/Services/JsonNetSerializer.cs index 51874c671c..6934b1a4ee 100644 --- a/src/Marten/Services/JsonNetSerializer.cs +++ b/src/Marten/Services/JsonNetSerializer.cs @@ -129,7 +129,7 @@ public Casing Casing } /// - /// Specify whether properties in the JSON document should use Camel or Pascal casing. + /// Specify whether collections should be stored as json arrays (without type names) /// public CollectionStorage CollectionStorage {