Skip to content

Commit 5dd7c8a

Browse files
committed
Merge branch 'fix/serialization-overrides'
Conflicts: src/Elasticsearch.Net/Configuration/ConnectionConfiguration.cs
2 parents 2ae1bd1 + 3febc70 commit 5dd7c8a

File tree

8 files changed

+74
-78
lines changed

8 files changed

+74
-78
lines changed

Diff for: src/Elasticsearch.Net/Configuration/ConnectionConfiguration.cs

+10-8
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ public ConnectionConfiguration(IConnectionPool connectionPool, IConnection conne
3838
: this(connectionPool, connection, null)
3939
{ }
4040

41-
public ConnectionConfiguration(IConnectionPool connectionPool, IElasticsearchSerializer serializer)
42-
: this(connectionPool, null, serializer)
41+
public ConnectionConfiguration(IConnectionPool connectionPool, Func<ConnectionConfiguration, IElasticsearchSerializer> serializerFactory)
42+
: this(connectionPool, null, serializerFactory)
4343
{ }
4444

4545
// ReSharper disable once MemberCanBePrivate.Global
4646
// eventhough we use don't use this we very much would like to expose this constructor
47-
public ConnectionConfiguration(IConnectionPool connectionPool, IConnection connection, IElasticsearchSerializer serializer)
48-
: base(connectionPool, connection, serializer)
47+
public ConnectionConfiguration(IConnectionPool connectionPool, IConnection connection, Func<ConnectionConfiguration, IElasticsearchSerializer> serializerFactory)
48+
: base(connectionPool, connection, serializerFactory)
4949
{ }
5050
}
5151

@@ -130,10 +130,11 @@ private static void DefaultApiCallHandler(IApiCallDetails status) { }
130130
BasicAuthenticationCredentials _basicAuthCredentials;
131131
BasicAuthenticationCredentials IConnectionConfigurationValues.BasicAuthenticationCredentials => _basicAuthCredentials;
132132

133-
private readonly IElasticsearchSerializer _serializer;
133+
protected IElasticsearchSerializer _serializer;
134134
IElasticsearchSerializer IConnectionConfigurationValues.Serializer => _serializer;
135135

136136
private readonly IConnectionPool _connectionPool;
137+
private readonly Func<T, IElasticsearchSerializer> _serializerFactory;
137138
IConnectionPool IConnectionConfigurationValues.ConnectionPool => _connectionPool;
138139

139140
private readonly IConnection _connection;
@@ -142,12 +143,13 @@ private static void DefaultApiCallHandler(IApiCallDetails status) { }
142143
[System.Diagnostics.CodeAnalysis.SuppressMessage(
143144
"Potential Code Quality Issues", "RECS0021:Warns about calls to virtual member functions occuring in the constructor",
144145
Justification = "We want the virtual method to run on most derived")]
145-
protected ConnectionConfiguration(IConnectionPool connectionPool, IConnection connection, IElasticsearchSerializer serializer)
146+
protected ConnectionConfiguration(IConnectionPool connectionPool, IConnection connection, Func<T, IElasticsearchSerializer> serializerFactory)
146147
{
147148
this._connectionPool = connectionPool;
148149
this._connection = connection ?? new HttpConnection();
150+
this._serializerFactory = serializerFactory ?? (c=>this.DefaultSerializer((T)this));
149151
// ReSharper disable once VirtualMemberCallInContructor
150-
this._serializer = serializer ?? this.DefaultSerializer();
152+
this._serializer = this._serializerFactory((T)this);
151153

152154
this._requestTimeout = ConnectionConfiguration.DefaultTimeout;
153155
this._sniffOnConnectionFault = true;
@@ -157,7 +159,7 @@ protected ConnectionConfiguration(IConnectionPool connectionPool, IConnection co
157159

158160
T Assign(Action<ConnectionConfiguration<T>> assigner) => Fluent.Assign((T)this, assigner);
159161

160-
protected virtual IElasticsearchSerializer DefaultSerializer() => new ElasticsearchDefaultSerializer();
162+
protected virtual IElasticsearchSerializer DefaultSerializer(T settings) => new ElasticsearchDefaultSerializer();
161163

162164
public T EnableTcpKeepAlive(TimeSpan keepAliveTime, TimeSpan keepAliveInterval) =>
163165
Assign(a => { this._keepAliveTime = keepAliveTime; this._keepAliveInterval = keepAliveInterval; });

Diff for: src/Nest/CommonAbstractions/ConnectionSettings/ConnectionSettings.cs

+7-36
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ public ConnectionSettings(IConnectionPool connectionPool)
2424
public ConnectionSettings(IConnectionPool connectionPool, IConnection connection)
2525
: this(connectionPool, connection, null) { }
2626

27-
public ConnectionSettings(IConnectionPool connectionPool, IElasticsearchSerializer serializer)
28-
: this(connectionPool, null, serializer) { }
27+
public ConnectionSettings(IConnectionPool connectionPool, Func<ConnectionSettings, IElasticsearchSerializer> serializerFactory)
28+
: this(connectionPool, null, serializerFactory) { }
2929

30-
public ConnectionSettings(IConnectionPool connectionPool, IConnection connection, IElasticsearchSerializer serializer)
31-
: base(connectionPool, connection, serializer) { }
30+
public ConnectionSettings(IConnectionPool connectionPool, IConnection connection, Func<ConnectionSettings, IElasticsearchSerializer> serializerFactory)
31+
: base(connectionPool, connection, serializerFactory) { }
3232
}
3333

3434
/// <summary>
@@ -57,37 +57,28 @@ public abstract class ConnectionSettings<TConnectionSettings> : ConnectionConfig
5757
private Func<string, string> _defaultFieldNameInferrer;
5858
Func<string, string> IConnectionSettingsValues.DefaultFieldNameInferrer => _defaultFieldNameInferrer;
5959

60-
//Serializer settings
61-
private Action<JsonSerializerSettings> _modifyJsonSerializerSettings;
62-
Action<JsonSerializerSettings> IConnectionSettingsValues.ModifyJsonSerializerSettings => _modifyJsonSerializerSettings;
63-
64-
private ReadOnlyCollection<Func<Type, JsonConverter>> _contractConverters;
65-
ReadOnlyCollection<Func<Type, JsonConverter>> IConnectionSettingsValues.ContractConverters => _contractConverters;
66-
6760
private readonly FluentDictionary<Type, string> _idProperties = new FluentDictionary<Type, string>();
6861
FluentDictionary<Type, string> IConnectionSettingsValues.IdProperties => _idProperties;
6962

7063
private readonly FluentDictionary<MemberInfo, IPropertyMapping> _propertyMappings = new FluentDictionary<MemberInfo, IPropertyMapping>();
7164
FluentDictionary<MemberInfo, IPropertyMapping> IConnectionSettingsValues.PropertyMappings => _propertyMappings;
7265

73-
protected ConnectionSettings(IConnectionPool connectionPool, IConnection connection, IElasticsearchSerializer serializer)
74-
: base(connectionPool, connection, serializer)
66+
protected ConnectionSettings(IConnectionPool connectionPool, IConnection connection, Func<TConnectionSettings, IElasticsearchSerializer> serializerFactory)
67+
: base(connectionPool, connection, serializerFactory)
7568
{
7669
this._defaultTypeNameInferrer = (t => t.Name.ToLowerInvariant());
7770
this._defaultFieldNameInferrer = (p => p.ToCamelCase());
7871
this._defaultIndices = new FluentDictionary<Type, string>();
7972
this._defaultTypeNames = new FluentDictionary<Type, string>();
8073

81-
this._modifyJsonSerializerSettings = j => { };
82-
this._contractConverters = Enumerable.Empty<Func<Type, JsonConverter>>().ToList().AsReadOnly();
8374
this._inferrer = new ElasticInferrer(this);
8475
}
8576

8677
/// <summary>
8778
/// The default serializer for requests and responses
8879
/// </summary>
8980
/// <returns></returns>
90-
protected override IElasticsearchSerializer DefaultSerializer() => new JsonNetSerializer(this);
81+
protected override IElasticsearchSerializer DefaultSerializer(TConnectionSettings settings) => new JsonNetSerializer(settings);
9182

9283
/// <summary>
9384
/// This calls SetDefaultTypenameInferrer with an implementation that will pluralize type names. This used to be the default prior to Nest 0.90
@@ -98,26 +89,6 @@ public TConnectionSettings PluralizeTypeNames()
9889
return (TConnectionSettings)this;
9990
}
10091

101-
/// <summary>
102-
/// Allows you to update internal the json.net serializer settings to your liking
103-
/// </summary>
104-
public TConnectionSettings JsonSerializerSettingsModifier(Action<JsonSerializerSettings> modifier)
105-
{
106-
if (modifier == null)
107-
return (TConnectionSettings)this;
108-
this._modifyJsonSerializerSettings = modifier;
109-
return (TConnectionSettings)this;
110-
111-
}
112-
/// <summary>
113-
/// Add a custom JsonConverter to the build in json serialization by passing in a predicate for a type.
114-
/// </summary>
115-
public TConnectionSettings AddContractJsonConverters(params Func<Type, JsonConverter>[] contractSelectors)
116-
{
117-
this._contractConverters = contractSelectors.ToList().AsReadOnly();
118-
return (TConnectionSettings)this;
119-
}
120-
12192
/// <summary>
12293
/// The default index to use when no index is specified.
12394
/// </summary>

Diff for: src/Nest/CommonAbstractions/ConnectionSettings/IConnectionSettingsValues.cs

-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,5 @@ public interface IConnectionSettingsValues : IConnectionConfigurationValues
1616
string DefaultIndex { get; }
1717
Func<string, string> DefaultFieldNameInferrer { get; }
1818
Func<Type, string> DefaultTypeNameInferrer { get; }
19-
Action<JsonSerializerSettings> ModifyJsonSerializerSettings { get; }
20-
ReadOnlyCollection<Func<Type, JsonConverter>> ContractConverters { get; }
2119
}
2220
}

Diff for: src/Nest/CommonAbstractions/Extensions/TypeExtensions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal static class TypeExtensions
2323

2424
//this contract is only used to resolve properties in class WE OWN.
2525
//these are not subject to change depending on what the user passes as connectionsettings
26-
private static ElasticContractResolver _jsonContract = new ElasticContractResolver(new ConnectionSettings());
26+
private static ElasticContractResolver _jsonContract = new ElasticContractResolver(new ConnectionSettings(), null);
2727

2828
public delegate T ObjectActivator<out T>(params object[] args);
2929

Diff for: src/Nest/CommonAbstractions/SerializationBehavior/ElasticContractResolver.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Nest
1212
{
1313
public class ElasticContractResolver : DefaultContractResolver
1414
{
15+
private readonly IList<Func<Type, JsonConverter>> _contractConverters;
1516
public static JsonSerializer Empty { get; } = new JsonSerializer();
1617

1718

@@ -25,8 +26,9 @@ public class ElasticContractResolver : DefaultContractResolver
2526
/// </summary>
2627
internal JsonConverterPiggyBackState PiggyBackState { get; set; }
2728

28-
public ElasticContractResolver(IConnectionSettingsValues connectionSettings)
29+
public ElasticContractResolver(IConnectionSettingsValues connectionSettings, IList<Func<Type, JsonConverter>> contractConverters)
2930
{
31+
this._contractConverters = contractConverters;
3032
this.ConnectionSettings = connectionSettings;
3133
}
3234

@@ -39,18 +41,18 @@ protected override JsonContract CreateContract(Type objectType)
3941

4042
if (typeof(IDictionary).IsAssignableFrom(objectType) && !typeof(IIsADictionary).IsAssignableFrom(objectType))
4143
contract.Converter = new VerbatimDictionaryKeysJsonConverter();
42-
else if (objectType == typeof(ServerError))
43-
contract.Converter = new ServerErrorJsonConverter();
44+
else if (objectType == typeof(ServerError))
45+
contract.Converter = new ServerErrorJsonConverter();
4446
else if (objectType == typeof(DateTime) || objectType == typeof(DateTime?))
4547
contract.Converter = new IsoDateTimeConverter();
4648
else if (!objectType.FullName.StartsWith("Nest.", StringComparison.OrdinalIgnoreCase)) return contract;
4749

4850
else if (ApplyExactContractJsonAttribute(objectType, contract)) return contract;
4951
else if (ApplyContractJsonAttribute(objectType, contract)) return contract;
5052

51-
if (this.ConnectionSettings.ContractConverters.HasAny())
53+
if (this._contractConverters.HasAny())
5254
{
53-
foreach (var c in this.ConnectionSettings.ContractConverters)
55+
foreach (var c in this._contractConverters)
5456
{
5557
var converter = c(objectType);
5658
if (converter == null)

Diff for: src/Nest/CommonAbstractions/SerializationBehavior/JsonNetSerializer.cs

+17-11
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,28 @@ public class JsonNetSerializer : IElasticsearchSerializer
1717
private readonly IConnectionSettingsValues _settings;
1818
private readonly Dictionary<SerializationFormatting, JsonSerializer> _defaultSerializers;
1919
private readonly JsonSerializer _defaultSerializer;
20+
internal JsonSerializer Serializer => _defaultSerializer;
21+
private ElasticContractResolver _contractResolver;
22+
23+
protected virtual void ModifyJsonSerializerSettings(JsonSerializerSettings settings) { }
24+
protected virtual IList<Func<Type, JsonConverter>> ContractConverters => null;
2025

2126
public JsonNetSerializer(IConnectionSettingsValues settings) : this(settings, null) { }
2227

2328
/// <summary>
2429
/// this constructor is only here for stateful (de)serialization
2530
/// </summary>
26-
public JsonNetSerializer(IConnectionSettingsValues settings, JsonConverter stateFullConverter)
31+
internal JsonNetSerializer(IConnectionSettingsValues settings, JsonConverter stateFullConverter)
2732
{
2833
this._settings = settings;
34+
var piggyBackState = stateFullConverter == null ? null : new JsonConverterPiggyBackState { ActualJsonConverter = stateFullConverter };
35+
// ReSharper disable once VirtualMemberCallInContructor
36+
this._contractResolver = new ElasticContractResolver(this._settings, this.ContractConverters) { PiggyBackState = piggyBackState };
2937

30-
this._defaultSerializer = JsonSerializer.Create(this.CreateSettings(SerializationFormatting.None, stateFullConverter));
31-
this._defaultSerializer.Formatting = Formatting.None;
32-
var indentedSerializer = JsonSerializer.Create(this.CreateSettings(SerializationFormatting.Indented, stateFullConverter));
33-
indentedSerializer.Formatting = Formatting.Indented;
38+
this._defaultSerializer = JsonSerializer.Create(this.CreateSettings(SerializationFormatting.None));
39+
//this._defaultSerializer.Formatting = Formatting.None;
40+
var indentedSerializer = JsonSerializer.Create(this.CreateSettings(SerializationFormatting.Indented));
41+
//indentedSerializer.Formatting = Formatting.Indented;
3442
this._defaultSerializers = new Dictionary<SerializationFormatting, JsonSerializer>
3543
{
3644
{ SerializationFormatting.None, this._defaultSerializer },
@@ -51,7 +59,7 @@ public void Serialize(object data, Stream writableStream, SerializationFormattin
5159
}
5260

5361
public string CreatePropertyName(MemberInfo memberInfo)
54-
{
62+
{
5563
var jsonProperty = memberInfo.GetCustomAttribute<JsonPropertyAttribute>(true);
5664
return jsonProperty?.PropertyName;
5765
}
@@ -74,22 +82,20 @@ public virtual T Deserialize<T>(Stream stream)
7482
return Task.FromResult<T>(result);
7583
}
7684

77-
internal JsonSerializerSettings CreateSettings(SerializationFormatting formatting, JsonConverter piggyBackJsonConverter = null)
85+
private JsonSerializerSettings CreateSettings(SerializationFormatting formatting)
7886
{
79-
var piggyBackState = new JsonConverterPiggyBackState { ActualJsonConverter = piggyBackJsonConverter };
8087
var settings = new JsonSerializerSettings()
8188
{
8289
Formatting = formatting == SerializationFormatting.Indented ? Formatting.Indented : Formatting.None,
83-
ContractResolver = new ElasticContractResolver(this._settings),
90+
ContractResolver = this._contractResolver,
8491
DefaultValueHandling = DefaultValueHandling.Include,
8592
NullValueHandling = NullValueHandling.Ignore
8693
};
8794

88-
_settings.ModifyJsonSerializerSettings?.Invoke(settings);
95+
this.ModifyJsonSerializerSettings(settings);
8996

9097
var contract = settings.ContractResolver as ElasticContractResolver;
9198
if (contract == null) throw new Exception($"NEST needs an instance of {nameof(ElasticContractResolver)} registered on Json.NET's JsonSerializerSettings");
92-
contract.PiggyBackState = piggyBackState;
9399

94100
return settings;
95101
}

Diff for: src/Nest/Search/MultiSearch/MultiSearchResponseJsonConverter.cs

+6-15
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,12 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
5959

6060
if (concreteTypeSelector != null)
6161
{
62-
var elasticSerializer = new JsonNetSerializer(this._settings);
6362
var state = typeof(ConcreteTypeConverter<>).CreateGenericInstance(baseType, concreteTypeSelector) as JsonConverter;
6463
if (state != null)
6564
{
66-
var settings = elasticSerializer.CreateSettings(SerializationFormatting.None, piggyBackJsonConverter: state);
67-
68-
var jsonSerializer = new JsonSerializer()
69-
{
70-
NullValueHandling = settings.NullValueHandling,
71-
DefaultValueHandling = settings.DefaultValueHandling,
72-
ContractResolver = settings.ContractResolver,
73-
};
74-
foreach (var converter in settings.Converters.EmptyIfNull())
75-
jsonSerializer.Converters.Add(converter);
76-
generic.Invoke(null, new object[] { m, jsonSerializer, response.Responses, this._settings });
65+
var elasticSerializer = new JsonNetSerializer(this._settings, state);
66+
67+
generic.Invoke(null, new object[] { m, elasticSerializer.Serializer, response.Responses, this._settings });
7768
continue;
7869
}
7970
}
@@ -104,10 +95,10 @@ IConnectionSettingsValues settings
10495
{
10596
var response = new SearchResponse<T>();
10697
var reader = tuple.Hit.CreateReader();
107-
serializer.Populate(reader, response);
108-
98+
serializer.Populate(reader, response);
99+
109100
ServerError error;
110-
if (tuple.Hit.TryParseServerError(serializer, out error))
101+
if (tuple.Hit.TryParseServerError(serializer, out error))
111102
response.MultiSearchError = error ;
112103

113104
collection.Add(tuple.Descriptor.Key, response);

Diff for: src/Tests/ClientConcepts/LowLevel/Connecting.doc.cs

+26
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Collections.Specialized;
34
using System.Net;
45
using Elasticsearch.Net;
6+
using FluentAssertions;
57
using Nest;
8+
using Newtonsoft.Json;
9+
using Tests.Framework;
610

711
namespace Tests.ClientConcepts.LowLevel
812
{
@@ -192,5 +196,27 @@ public void ConfiguringSSL()
192196
* therefore we recommend doing some minimal introspection on the passed in certificate.
193197
*/
194198
}
199+
200+
public class MyJsonNetSerializer : JsonNetSerializer
201+
{
202+
public int X { get; set; } = 0;
203+
public MyJsonNetSerializer(IConnectionSettingsValues settings) : base(settings) { }
204+
205+
protected override void ModifyJsonSerializerSettings(JsonSerializerSettings settings)
206+
{
207+
++X;
208+
}
209+
}
210+
211+
[U] public void IsCalled()
212+
{
213+
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
214+
var settings = new ConnectionSettings(connectionPool, new InMemoryConnection(),s => new MyJsonNetSerializer(s));
215+
var client = new ElasticClient(settings);
216+
client.RootNodeInfo();
217+
client.RootNodeInfo();
218+
var serializer = ((IConnectionSettingsValues)settings).Serializer as MyJsonNetSerializer;
219+
serializer.X.Should().BeGreaterThan(0);
220+
}
195221
}
196222
}

0 commit comments

Comments
 (0)