Skip to content

Commit 824bfa2

Browse files
committed
Updated JsonNetSerializer implementation, so that its default contract resolver is aware of connection settings and its config
1 parent 463ec9b commit 824bfa2

File tree

21 files changed

+324
-112
lines changed

21 files changed

+324
-112
lines changed

src/Elasticsearch.Net/Connection/HttpConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ protected virtual HttpWebRequest CreateWebRequest(RequestData requestData)
6060
request.Accept = requestData.Accept;
6161
request.ContentType = requestData.ContentType;
6262
request.MaximumResponseHeadersLength = -1;
63-
request.AllowWriteStreamBuffering = false;
63+
//request.AllowWriteStreamBuffering = false;
6464
request.Pipelined = requestData.Pipelined;
6565

6666
if (requestData.HttpCompression)

src/Nest/CommonAbstractions/ConnectionSettings/ConnectionSettingsBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Nest
1414
/// </summary>
1515
public class ConnectionSettings : ConnectionSettingsBase<ConnectionSettings>
1616
{
17-
public delegate IElasticsearchSerializer SourceSerializerFactory(IConnectionSettingsValues values, IElasticsearchSerializer builtIn);
17+
public delegate IElasticsearchSerializer SourceSerializerFactory(IElasticsearchSerializer builtIn, IConnectionSettingsValues values);
1818

1919
public ConnectionSettings(Uri uri = null)
2020
: this(new SingleNodeConnectionPool(uri ?? new Uri("http://localhost:9200"))) { }
@@ -89,7 +89,7 @@ IPropertyMappingProvider propertyMappingProvider
8989
: base(connectionPool, connection, null)
9090
{
9191
var defaultSerializer = new JsonNetSerializer(this);
92-
this._sourceSerializer = sourceSerializerFactory?.Invoke(this, defaultSerializer) ?? defaultSerializer;
92+
this._sourceSerializer = sourceSerializerFactory?.Invoke(defaultSerializer, this) ?? defaultSerializer;
9393
this.UseThisRequestResponseSerializer = defaultSerializer;
9494
this._propertyMappingProvider = propertyMappingProvider ?? new PropertyMappingProvider();
9595

@@ -212,7 +212,7 @@ private void ApplyPropertyMappings<TDocument>(IList<IClrTypePropertyMapping<TDoc
212212
throw new ArgumentException($"Property mapping '{e}' on type {typeName} can not be ignored it already has a mapping to '{mappedAs}'");
213213
throw new ArgumentException($"Property mapping '{e}' on type {typeName} can not be mapped to '{newName}' already mapped as '{mappedAs}'");
214214
}
215-
_propertyMappings.Add(memberInfo, mapping.ToPropertyMapping());
215+
_propertyMappings[memberInfo] = mapping.ToPropertyMapping();
216216
}
217217
}
218218

src/Nest/CommonAbstractions/SerializationBehavior/ElasticContractResolver.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,10 @@ protected override JsonContract CreateContract(Type objectType)
5050
contract.Converter = new QueryContainerCollectionJsonConverter();
5151
else if (o == typeof(ServerError))
5252
contract.Converter = new ServerErrorJsonConverter();
53-
else if (o == typeof(DateTime) ||
54-
o == typeof(DateTime?))
53+
else if (o == typeof(DateTime) || o == typeof(DateTime?))
5554
contract.Converter = new IsoDateTimeConverter { Culture = CultureInfo.InvariantCulture };
56-
else if (o == typeof(TimeSpan) ||
57-
o == typeof(TimeSpan?))
58-
contract.Converter = new TimeSpanConverter();
55+
else if (o == typeof(TimeSpan) || o == typeof(TimeSpan?))
56+
contract.Converter = new TimeSpanToStringConverter();
5957

6058
ApplyBuildInSerializersForType(o, contract);
6159

src/Nest/CommonAbstractions/SerializationBehavior/GenericJsonConverters/ServerErrorJsonConverter.cs

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@
66
namespace Nest
77
{
88
internal class ServerErrorJsonConverter : JsonConverter
9-
{
9+
{
1010
public override bool CanRead => true;
1111
public override bool CanWrite => false;
1212
public override bool CanConvert(Type objectType) => objectType == typeof(ServerError);
1313

14-
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }
15-
16-
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
17-
{
18-
var token = JToken.Load(reader);
19-
ServerError error = null;
20-
token.TryParseServerError(serializer, out error);
21-
return error;
22-
}
14+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }
15+
16+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
17+
{
18+
var token = JToken.Load(reader);
19+
token.TryParseServerError(serializer, out var error);
20+
return error;
21+
}
2322
}
24-
}
23+
}

src/Nest/CommonAbstractions/SerializationBehavior/GenericJsonConverters/TimeSpanConverter.cs renamed to src/Nest/CommonAbstractions/SerializationBehavior/GenericJsonConverters/TimeSpanToStringConverter.cs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Globalization;
4-
using System.Reflection;
52
using Newtonsoft.Json;
6-
using Newtonsoft.Json.Linq;
73

84
namespace Nest
95
{
10-
internal class TimeSpanConverter : JsonConverter
6+
internal class TimeSpanToStringConverter : JsonConverter
117
{
128
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
139
{
@@ -22,22 +18,12 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
2218

2319
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
2420
{
25-
if (reader.TokenType == JsonToken.Null)
21+
switch (reader.TokenType)
2622
{
27-
if (!objectType.IsGeneric() || objectType.GetGenericTypeDefinition() != typeof (Nullable<>))
28-
throw new JsonSerializationException($"Cannot convert null value to {objectType}.");
29-
30-
return null;
31-
}
32-
if (reader.TokenType == JsonToken.String)
33-
{
34-
return TimeSpan.Parse((string) reader.Value);
23+
case JsonToken.Null: return null;
24+
case JsonToken.String: return TimeSpan.Parse((string) reader.Value);
25+
case JsonToken.Integer: return new TimeSpan((long) reader.Value);
3526
}
36-
if (reader.TokenType == JsonToken.Integer)
37-
{
38-
return new TimeSpan((long) reader.Value);
39-
}
40-
4127
throw new JsonSerializationException($"Cannot convert token of type {reader.TokenType} to {objectType}.");
4228
}
4329

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using Newtonsoft.Json;
6+
using Newtonsoft.Json.Serialization;
7+
8+
namespace Nest.JsonNetSerializer
9+
{
10+
public class ConnectionSettingsAwareContractResolver : DefaultContractResolver
11+
{
12+
private readonly IConnectionSettingsValues _connectionSettings;
13+
14+
public ConnectionSettingsAwareContractResolver(IConnectionSettingsValues connectionSettings)
15+
{
16+
_connectionSettings = connectionSettings ?? throw new ArgumentNullException(nameof(connectionSettings));
17+
}
18+
19+
protected override string ResolvePropertyName(string fieldName) =>
20+
this._connectionSettings.DefaultFieldNameInferrer != null
21+
? this._connectionSettings.DefaultFieldNameInferrer(fieldName)
22+
: base.ResolvePropertyName(fieldName);
23+
24+
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
25+
{
26+
var property = base.CreateProperty(member, memberSerialization);
27+
ApplyShouldSerializer(property);
28+
ApplyPropertyOverrides(member, property);
29+
return property;
30+
}
31+
32+
/// <summary> Renames/Ignores a property based on the connection settings mapping or custom attributes for the property </summary>
33+
private void ApplyPropertyOverrides(MemberInfo member, JsonProperty property)
34+
{
35+
if (!this._connectionSettings.PropertyMappings.TryGetValue(member, out var propertyMapping))
36+
propertyMapping = ElasticsearchPropertyAttributeBase.From(member);
37+
38+
var serializerMapping = this._connectionSettings.PropertyMappingProvider?.CreatePropertyMapping(member);
39+
40+
var nameOverride = propertyMapping?.Name ?? serializerMapping?.Name;
41+
if (!string.IsNullOrWhiteSpace(nameOverride)) property.PropertyName = nameOverride;
42+
43+
var overrideIgnore = propertyMapping?.Ignore ?? serializerMapping?.Ignore;
44+
if (overrideIgnore.HasValue)
45+
property.Ignored = overrideIgnore.Value;
46+
}
47+
48+
private static void ApplyShouldSerializer(JsonProperty property)
49+
{
50+
if (property.PropertyType == typeof(QueryContainer))
51+
property.ShouldSerialize = o => ShouldSerializeQueryContainer(o, property);
52+
else if (property.PropertyType == typeof(IEnumerable<QueryContainer>))
53+
property.ShouldSerialize = o => ShouldSerializeQueryContainers(o, property);
54+
}
55+
56+
private static bool ShouldSerializeQueryContainer(object o, JsonProperty prop)
57+
{
58+
if (o == null) return false;
59+
if (!(prop.ValueProvider.GetValue(o) is QueryContainer q)) return false;
60+
if (((IQueryContainer)q).IsWritable) return true;
61+
var nq = q as NoMatchQueryContainer;
62+
return nq?.Shortcut != null;
63+
}
64+
65+
private static bool ShouldSerializeQueryContainers(object o, JsonProperty prop)
66+
{
67+
if (o == null) return false;
68+
if (!(prop.ValueProvider.GetValue(o) is IEnumerable<QueryContainer> q)) return false;
69+
var queryContainers = q as QueryContainer[] ?? q.ToArray();
70+
return queryContainers.Any(qq=>qq != null && ((IQueryContainer)qq).IsWritable);
71+
}
72+
73+
}
74+
}

src/Serializers/Nest.JsonNetSerializer/JsonNetSourceSerializerBase.cs renamed to src/Serializers/Nest.JsonNetSerializer/ConnectionSettingsAwareSerializerBase.Customization.cs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,22 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.IO;
4-
using System.Linq;
53
using System.Text;
64
using System.Threading;
75
using System.Threading.Tasks;
86
using Elasticsearch.Net;
97
using Newtonsoft.Json;
108
using Newtonsoft.Json.Linq;
11-
using Newtonsoft.Json.Serialization;
129

1310
namespace Nest.JsonNetSerializer
1411
{
15-
public abstract class JsonNetSourceSerializerBase : IElasticsearchSerializer
12+
public abstract partial class ConnectionSettingsAwareSerializerBase : IElasticsearchSerializer
1613
{
17-
protected IElasticsearchSerializer BuiltinSerializer { get; }
1814
private static readonly Encoding ExpectedEncoding = new UTF8Encoding(false);
1915
protected virtual int BufferSize => 1024;
2016

2117
private readonly JsonSerializer _serializer;
2218
private readonly JsonSerializer _collapsedSerializer;
2319

24-
protected JsonNetSourceSerializerBase(IElasticsearchSerializer builtinSerializer)
25-
{
26-
BuiltinSerializer = builtinSerializer;
27-
_serializer = CreateSerializer(SerializationFormatting.Indented);
28-
_collapsedSerializer = CreateSerializer(SerializationFormatting.None);
29-
}
30-
31-
protected abstract JsonSerializerSettings CreateJsonSerializerSettings();
32-
protected abstract IEnumerable<JsonConverter> CreateJsonConverters();
33-
protected virtual IContractResolver CreateContractResolver() => new DefaultContractResolver();
34-
35-
private JsonSerializer CreateSerializer(SerializationFormatting formatting)
36-
{
37-
var s = CreateJsonSerializerSettings();
38-
var converters = CreateJsonConverters() ?? Enumerable.Empty<JsonConverter>();
39-
var contract = CreateContractResolver();
40-
s.Formatting = formatting == SerializationFormatting.Indented ? Formatting.Indented : Formatting.None;
41-
s.ContractResolver = contract;
42-
s.Converters = converters.Concat(new List<JsonConverter>
43-
{
44-
new RevertBackToBuiltinSerializer(BuiltinSerializer)
45-
}).ToList();
46-
return JsonSerializer.Create(s);
47-
}
48-
4920
public T Deserialize<T>(Stream stream)
5021
{
5122
using (var streamReader = new StreamReader(stream))
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Elasticsearch.Net;
5+
using Newtonsoft.Json;
6+
using Newtonsoft.Json.Serialization;
7+
using Nest.JsonNetSerializer.Converters;
8+
9+
namespace Nest.JsonNetSerializer
10+
{
11+
public abstract partial class ConnectionSettingsAwareSerializerBase
12+
{
13+
protected IConnectionSettingsValues ConnectionSettings { get; }
14+
protected IElasticsearchSerializer BuiltinSerializer { get; }
15+
16+
private List<JsonConverter> Converters { get; }
17+
18+
protected ConnectionSettingsAwareSerializerBase(
19+
IElasticsearchSerializer builtinSerializer,
20+
IConnectionSettingsValues connectionSettings)
21+
{
22+
ConnectionSettings = connectionSettings;
23+
BuiltinSerializer = builtinSerializer;
24+
this.Converters = new List<JsonConverter>
25+
{
26+
new RevertBackToBuiltinSerializer(BuiltinSerializer),
27+
new TimeSpanToStringConverter()
28+
};
29+
_serializer = CreateSerializer(SerializationFormatting.Indented);
30+
_collapsedSerializer = CreateSerializer(SerializationFormatting.None);
31+
32+
}
33+
34+
private JsonSerializer CreateSerializer(SerializationFormatting formatting)
35+
{
36+
var s = CreateJsonSerializerSettings();
37+
var converters = CreateJsonConverters() ?? Enumerable.Empty<JsonConverter>();
38+
var contract = CreateContractResolver();
39+
s.Formatting = formatting == SerializationFormatting.Indented ? Formatting.Indented : Formatting.None;
40+
s.ContractResolver = contract;
41+
s.Converters = converters.Concat(this.Converters).ToList();
42+
return JsonSerializer.Create(s);
43+
}
44+
private IContractResolver CreateContractResolver()
45+
{
46+
var contract = new ConnectionSettingsAwareContractResolver(this.ConnectionSettings);
47+
ModifyContractResolver(contract);
48+
return contract;
49+
}
50+
51+
protected abstract JsonSerializerSettings CreateJsonSerializerSettings();
52+
53+
protected abstract IEnumerable<JsonConverter> CreateJsonConverters();
54+
55+
protected virtual void ModifyContractResolver(ConnectionSettingsAwareContractResolver resolver) { }
56+
}
57+
58+
public class JsonNetSerializer : ConnectionSettingsAwareSerializerBase
59+
{
60+
private readonly Func<JsonSerializerSettings> _jsonSerializerSettingsFactory;
61+
private readonly Action<ConnectionSettingsAwareContractResolver> _modifyContractResolver;
62+
private readonly IEnumerable<JsonConverter> _contractJsonConverters;
63+
64+
public static IElasticsearchSerializer Default(IElasticsearchSerializer builtin, IConnectionSettingsValues values)
65+
=> new JsonNetSerializer(builtin, values);
66+
67+
public JsonNetSerializer(
68+
IElasticsearchSerializer builtinSerializer,
69+
IConnectionSettingsValues connectionSettings,
70+
Func<JsonSerializerSettings> jsonSerializerSettingsFactory = null,
71+
Action<ConnectionSettingsAwareContractResolver> modifyContractResolver = null,
72+
IEnumerable<JsonConverter> contractJsonConverters = null)
73+
: base(builtinSerializer, connectionSettings)
74+
{
75+
_jsonSerializerSettingsFactory = jsonSerializerSettingsFactory;
76+
_modifyContractResolver = modifyContractResolver;
77+
_contractJsonConverters = contractJsonConverters ?? Enumerable.Empty<JsonConverter>();
78+
}
79+
80+
protected override JsonSerializerSettings CreateJsonSerializerSettings() => _jsonSerializerSettingsFactory?.Invoke();
81+
82+
protected override IEnumerable<JsonConverter> CreateJsonConverters() => _contractJsonConverters;
83+
84+
protected override void ModifyContractResolver(ConnectionSettingsAwareContractResolver resolver) =>
85+
_modifyContractResolver?.Invoke(resolver);
86+
87+
}
88+
}

src/Serializers/Nest.JsonNetSerializer/RevertBackToBuiltinSerializer.cs renamed to src/Serializers/Nest.JsonNetSerializer/Converters/RevertBackToBuiltinSerializer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
using Newtonsoft.Json;
77
using Newtonsoft.Json.Linq;
88

9-
namespace Nest.JsonNetSerializer
9+
namespace Nest.JsonNetSerializer.Converters
1010
{
1111
internal class RevertBackToBuiltinSerializer : JsonConverter
1212
{
@@ -41,6 +41,5 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
4141
};
4242

4343
public override bool CanConvert(Type objectType) => NestTypesThatCanAppearInSource.Contains(objectType);
44-
4544
}
4645
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using Newtonsoft.Json;
3+
4+
namespace Nest.JsonNetSerializer.Converters
5+
{
6+
/// <summary>
7+
/// Included for compatibility reasons
8+
/// </summary>
9+
internal class TimeSpanToStringConverter : JsonConverter
10+
{
11+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
12+
{
13+
if (value == null)
14+
writer.WriteNull();
15+
else
16+
{
17+
var timeSpan = (TimeSpan) value;
18+
writer.WriteValue(timeSpan.Ticks);
19+
}
20+
}
21+
22+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
23+
{
24+
switch (reader.TokenType)
25+
{
26+
case JsonToken.Null: return null;
27+
case JsonToken.String: return TimeSpan.Parse((string) reader.Value);
28+
case JsonToken.Integer: return new TimeSpan((long) reader.Value);
29+
}
30+
throw new JsonSerializationException($"Cannot convert token of type {reader.TokenType} to {objectType}.");
31+
}
32+
33+
public override bool CanConvert(Type objectType) => objectType == typeof (TimeSpan) || objectType == typeof (TimeSpan?);
34+
}
35+
}

0 commit comments

Comments
 (0)