Skip to content

Commit 044f557

Browse files
authored
Use ContractJsonConverterAttribute where possible (#3653)
This commit changes usage of JsonConverterAttribute to using ContractJsonConverterAttribute where possible. This commit updates the CreateContract method in ElasticContractResolver to short-circuit if the type is attributed with ContractJsonConverterAttribute or ExactContractJsonConverterAttribute. This avoids going through superfluous steps in base.CreateContract().
1 parent 271685c commit 044f557

File tree

70 files changed

+129
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+129
-132
lines changed

src/Nest/Cat/CatFielddata/CatFielddataRecord.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Nest
44
{
55
[JsonObject]
6-
[JsonConverter(typeof(CatFielddataRecordJsonConverter))]
6+
[ContractJsonConverter(typeof(CatFielddataRecordJsonConverter))]
77
public class CatFielddataRecord : ICatRecord
88
{
99
public string Field { get; set; }

src/Nest/CommonAbstractions/Extensions/TypeExtensions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ internal static object CreateGenericInstance(this Type t, Type[] closeOver, para
5353
return closedType.CreateInstance(args);
5454
}
5555

56+
internal static T CreateGenericInstance<T>(this Type t, Type[] closeOver, params object[] args) =>
57+
(T)CreateGenericInstance(t, closeOver, args);
58+
5659
internal static T CreateInstance<T>(this Type t, params object[] args) => (T)t.CreateInstance(args);
5760

5861
internal static object CreateInstance(this Type t, params object[] args)

src/Nest/CommonAbstractions/Infer/Field/Field.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Nest
1111
/// <summary>
1212
/// A field within Elasticsearch
1313
/// </summary>
14-
[JsonConverter(typeof(FieldJsonConverter))]
14+
[ContractJsonConverter(typeof(FieldJsonConverter))]
1515
[DebuggerDisplay("{DebugDisplay,nq}")]
1616
public class Field : IEquatable<Field>, IUrlParameter
1717
{

src/Nest/CommonAbstractions/Infer/Fields/Fields.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace Nest
1212
{
13-
[JsonConverter(typeof(FieldsJsonConverter))]
13+
[ContractJsonConverter(typeof(FieldsJsonConverter))]
1414
[DebuggerDisplay("{DebugDisplay,nq}")]
1515
public class Fields : IUrlParameter, IEnumerable<Field>, IEquatable<Fields>
1616
{

src/Nest/CommonAbstractions/Infer/Id/Id.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace Nest
88
{
9-
[JsonConverter(typeof(IdJsonConverter))]
9+
[ContractJsonConverter(typeof(IdJsonConverter))]
1010
[DebuggerDisplay("{DebugDisplay,nq}")]
1111
public class Id : IEquatable<Id>, IUrlParameter
1212
{

src/Nest/CommonAbstractions/Infer/JoinFieldRouting/Routing.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Nest
99
{
10-
[JsonConverter(typeof(RoutingJsonConverter))]
10+
[ContractJsonConverter(typeof(RoutingJsonConverter))]
1111
[DebuggerDisplay("{DebugDisplay,nq}")]
1212
public class Routing : IEquatable<Routing>, IUrlParameter
1313
{

src/Nest/CommonAbstractions/SerializationBehavior/ElasticContractResolver.cs

Lines changed: 59 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@ namespace Nest
1313
{
1414
internal class ElasticContractResolver : DefaultContractResolver
1515
{
16-
private static readonly Type _readAsType = typeof(ReadAsTypeJsonConverter<>);
17-
private static readonly MachineLearningDateTimeConverter MachineLearningDateTimeConverter = new MachineLearningDateTimeConverter();
16+
private static readonly Type[] StringSignalTypes = { typeof(KeywordAttribute), typeof(TextAttribute) };
17+
private static readonly Assembly ThisAssembly = typeof(ElasticContractResolver).Assembly();
1818

19+
private static readonly MachineLearningDateTimeConverter MachineLearningDateTimeConverter = new MachineLearningDateTimeConverter();
1920
private static readonly StringEnumConverter StringEnumConverter = new StringEnumConverter();
20-
private static readonly Type[] StringSignalTypes = { typeof(KeywordAttribute), typeof(TextAttribute) };
2121
private static readonly StringTimeSpanConverter StringTimeSpanConverter = new StringTimeSpanConverter();
22+
private static readonly TimeSpanToStringConverter TimeSpanToStringConverter = new TimeSpanToStringConverter();
23+
private static readonly QueryContainerCollectionJsonConverter QueryContainerCollectionJsonConverter = new QueryContainerCollectionJsonConverter();
24+
private static readonly IsoDateTimeConverter IsoDateTimeConverter = new IsoDateTimeConverter { Culture = CultureInfo.InvariantCulture };
25+
private static readonly VerbatimDictionaryKeysJsonConverter VerbatimDictionaryKeysJsonConverter = new VerbatimDictionaryKeysJsonConverter();
26+
private static readonly ErrorJsonConverter ErrorJsonConverter = new ErrorJsonConverter();
27+
private static readonly ErrorCauseJsonConverter ErrorCauseJsonConverter = new ErrorCauseJsonConverter();
2228

23-
private static readonly Assembly ThisAssembly = typeof(ElasticContractResolver).Assembly();
2429
private readonly Lazy<bool> _usingSourceSerializer;
2530

2631
public ElasticContractResolver(IConnectionSettingsValues connectionSettings)
@@ -34,8 +39,14 @@ public ElasticContractResolver(IConnectionSettingsValues connectionSettings)
3439
/// </summary>
3540
public IConnectionSettingsValues ConnectionSettings { get; }
3641

42+
/// <summary>
43+
/// A JsonSerializer with defaults
44+
/// </summary>
3745
public static JsonSerializer Empty { get; } = new JsonSerializer();
3846

47+
/// <summary>
48+
/// Determines whether a custom source serializer is being used rather than the internal serializer
49+
/// </summary>
3950
public bool UsingSourceSerializer => _usingSourceSerializer.Value;
4051

4152
/// <summary>
@@ -46,43 +57,45 @@ public ElasticContractResolver(IConnectionSettingsValues connectionSettings)
4657
protected bool CanRemoveSourceConverter(JsonConverter converter)
4758
{
4859
if (UsingSourceSerializer || converter == null) return false;
49-
5060
return converter is SourceConverter;
5161
}
5262

5363
protected override JsonContract CreateContract(Type objectType) => ConnectionSettings.Inferrer.Contracts.GetOrAdd(objectType, o =>
5464
{
55-
var contract = base.CreateContract(o);
56-
57-
if (o == typeof(Error)) contract.Converter = new ErrorJsonConverter();
58-
else if (o == typeof(ErrorCause)) contract.Converter = new ErrorCauseJsonConverter();
59-
else if (CanRemoveSourceConverter(contract.Converter)) contract.Converter = null; //rely on defaults
60-
else if (o.IsGeneric() && o.GetGenericTypeDefinition() == typeof(SuggestDictionary<>))
61-
contract.Converter =
62-
(JsonConverter)typeof(SuggestDictionaryConverter<>).CreateGenericInstance(o.GetGenericArguments());
65+
JsonContract contract;
6366

64-
else if (contract.Converter == null &&
65-
(typeof(IDictionary).IsAssignableFrom(o) || o.IsGenericDictionary()) && !typeof(IIsADictionary).IsAssignableFrom(o))
67+
// short circuit for types with converters
68+
if (o.Assembly == ThisAssembly)
6669
{
67-
if (!o.TryGetGenericDictionaryArguments(out var genericArguments))
68-
contract.Converter = new VerbatimDictionaryKeysJsonConverter();
69-
else
70-
contract.Converter =
71-
(JsonConverter)typeof(VerbatimDictionaryKeysJsonConverter<,>).CreateGenericInstance(genericArguments);
70+
var converter = GetContractJsonConverter(o);
71+
if (converter != null)
72+
{
73+
contract = CreateObjectContract(o);
74+
contract.Converter = converter;
75+
return contract;
76+
}
7277
}
7378

79+
contract = base.CreateContract(o);
80+
81+
if (CanRemoveSourceConverter(contract.Converter)) contract.Converter = null; //rely on defaults
82+
else if (o == typeof(Error)) contract.Converter = ErrorJsonConverter;
83+
else if (o == typeof(ErrorCause)) contract.Converter = ErrorCauseJsonConverter;
84+
else if (o.IsGeneric() && o.GetGenericTypeDefinition() == typeof(SuggestDictionary<>))
85+
contract.Converter = typeof(SuggestDictionaryConverter<>).CreateGenericInstance<JsonConverter>(o.GetGenericArguments());
86+
else if (contract.Converter == null &&
87+
(typeof(IDictionary).IsAssignableFrom(o) || o.IsGenericDictionary()) && !typeof(IIsADictionary).IsAssignableFrom(o))
88+
contract.Converter = !o.TryGetGenericDictionaryArguments(out var genericArguments)
89+
? VerbatimDictionaryKeysJsonConverter
90+
: typeof(VerbatimDictionaryKeysJsonConverter<,>).CreateGenericInstance<JsonConverter>(genericArguments);
7491
else if (o == typeof(DateTime) || o == typeof(DateTime?))
75-
contract.Converter = new IsoDateTimeConverter { Culture = CultureInfo.InvariantCulture };
92+
contract.Converter = IsoDateTimeConverter;
7693
else if (o == typeof(TimeSpan) || o == typeof(TimeSpan?))
77-
contract.Converter = new TimeSpanToStringConverter();
94+
contract.Converter = TimeSpanToStringConverter;
7895
else if (typeof(IEnumerable<QueryContainer>).IsAssignableFrom(o))
79-
contract.Converter = new QueryContainerCollectionJsonConverter();
80-
81-
ApplyBuildInSerializersForType(o, contract);
82-
83-
if (!o.FullName.StartsWith("Nest.", StringComparison.OrdinalIgnoreCase)) return contract;
84-
if (ApplyExactContractJsonAttribute(o, contract)) return contract;
85-
if (ApplyContractJsonAttribute(o, contract)) return contract;
96+
contract.Converter = QueryContainerCollectionJsonConverter;
97+
else if (o.GetTypeInfo().GetCustomAttribute<StringEnumAttribute>() != null)
98+
contract.Converter = StringEnumConverter;
8699

87100
return contract;
88101
});
@@ -96,41 +109,37 @@ protected override JsonConverter ResolveContractConverter(Type objectType)
96109

97110
var readAsType = attribute.Type;
98111
var readAsTypeInfo = readAsType.GetTypeInfo();
112+
var readAsJsonConverterType = typeof(ReadAsTypeJsonConverter<>);
99113
if (!readAsTypeInfo.IsGenericType || !readAsTypeInfo.IsGenericTypeDefinition)
100-
return (JsonConverter)_readAsType.CreateGenericInstance(objectType);
114+
return (JsonConverter)readAsJsonConverterType.CreateGenericInstance(objectType);
101115

102116
var targetType = objectType;
103117
if (info.IsGenericType) targetType = targetType.GetGenericArguments().First();
104118

105119
var concreteType = readAsType.MakeGenericType(targetType);
106-
return (JsonConverter)_readAsType.CreateGenericInstance(concreteType);
120+
return (JsonConverter)readAsJsonConverterType.CreateGenericInstance(concreteType);
107121
}
108122

109-
private static bool ApplyExactContractJsonAttribute(Type objectType, JsonContract contract)
123+
private static JsonConverter GetContractJsonConverter(Type objectType)
110124
{
111-
var attribute = (ExactContractJsonConverterAttribute)objectType.GetTypeInfo()
125+
var exactAttribute = (ExactContractJsonConverterAttribute)objectType.GetTypeInfo()
112126
.GetCustomAttributes(typeof(ExactContractJsonConverterAttribute))
113127
.FirstOrDefault();
114-
if (attribute?.Converter == null) return false;
115128

116-
contract.Converter = attribute.Converter;
117-
return true;
118-
}
129+
if (exactAttribute?.Converter != null)
130+
return exactAttribute.Converter;
119131

120-
private static bool ApplyContractJsonAttribute(Type objectType, JsonContract contract)
121-
{
122132
foreach (var t in TypeWithInterfaces(objectType))
123133
{
124-
var attribute =
125-
(ContractJsonConverterAttribute)t.GetTypeInfo()
126-
.GetCustomAttributes(typeof(ContractJsonConverterAttribute), true)
127-
.FirstOrDefault();
134+
var attribute = (ContractJsonConverterAttribute)t.GetTypeInfo()
135+
.GetCustomAttributes(typeof(ContractJsonConverterAttribute), true)
136+
.FirstOrDefault();
128137
if (attribute?.Converter == null) continue;
129138

130-
contract.Converter = attribute.Converter;
131-
return true;
139+
return attribute.Converter;
132140
}
133-
return false;
141+
142+
return null;
134143
}
135144

136145
private static IEnumerable<Type> TypeWithInterfaces(Type objectType)
@@ -150,13 +159,12 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ
150159
if (member.Name == nameof(IResponse.ApiCall) && typeof(IResponse).IsAssignableFrom(member.DeclaringType))
151160
property.Ignored = true;
152161

153-
ApplyShouldSerializer(property);
162+
ApplyShouldSerialize(property);
154163
ApplyPropertyOverrides(member, property);
155-
ApplyBuildInSerializers(member, property);
164+
ApplyBuiltInConverters(member, property);
156165
return property;
157166
}
158167

159-
160168
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
161169
{
162170
// Only serialize explicitly implemented IProperty properties on attribute types
@@ -167,10 +175,6 @@ protected override IList<JsonProperty> CreateProperties(Type type, MemberSeriali
167175
if (typeof(IDescriptor).IsAssignableFrom(type))
168176
return PropertiesOfAll(type, memberSerialization);
169177

170-
var nativeType = type.Assembly() == ThisAssembly;
171-
if (nativeType)
172-
return base.CreateProperties(type, memberSerialization);
173-
174178
return base.CreateProperties(type, memberSerialization);
175179
}
176180

@@ -232,7 +236,7 @@ protected bool ShouldSerializeRouting(object o, JsonProperty prop)
232236
return !resolved.IsNullOrEmpty();
233237
}
234238

235-
private static void ApplyBuildInSerializers(MemberInfo member, JsonProperty property)
239+
private static void ApplyBuiltInConverters(MemberInfo member, JsonProperty property)
236240
{
237241
var attributes = member.GetCustomAttributes().ToList();
238242
var stringy = attributes.Any(a => StringSignalTypes.Contains(a.GetType()));
@@ -248,12 +252,6 @@ private static void ApplyBuildInSerializers(MemberInfo member, JsonProperty prop
248252
property.Converter = MachineLearningDateTimeConverter;
249253
}
250254

251-
private static void ApplyBuildInSerializersForType(Type type, JsonContract contract)
252-
{
253-
if (type.GetTypeInfo().GetCustomAttribute<StringEnumAttribute>() != null)
254-
contract.Converter = StringEnumConverter;
255-
}
256-
257255
/// <summary> Renames/Ignores a property based on the connection settings mapping or custom attributes for the property </summary>
258256
private void ApplyPropertyOverrides(MemberInfo member, JsonProperty property)
259257
{
@@ -270,7 +268,7 @@ private void ApplyPropertyOverrides(MemberInfo member, JsonProperty property)
270268
property.Ignored = overrideIgnore.Value;
271269
}
272270

273-
private void ApplyShouldSerializer(JsonProperty property)
271+
private void ApplyShouldSerialize(JsonProperty property)
274272
{
275273
if (property.PropertyType == typeof(QueryContainer))
276274
property.ShouldSerialize = o => ShouldSerializeQueryContainer(o, property);

src/Nest/CrossPlatform/TypeExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
using System.Runtime.CompilerServices;
56

67
namespace Nest
78
{

src/Nest/QueryDsl/Specialized/MoreLikeThis/Like/LikeDocument.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace Nest
55
{
66
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
7-
[JsonConverter(typeof(ReadAsTypeJsonConverter<LikeDocument<object>>))]
7+
[ContractJsonConverter(typeof(ReadAsTypeJsonConverter<LikeDocument<object>>))]
88
public interface ILikeDocument
99
{
1010
[JsonProperty("doc")]

src/Nest/QueryDsl/Specialized/MoreLikeThis/MoreLikeThisQuery.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace Nest
88
{
99
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
10-
[JsonConverter(typeof(ReadAsTypeJsonConverter<MoreLikeThisQueryDescriptor<object>>))]
10+
[ContractJsonConverter(typeof(ReadAsTypeJsonConverter<MoreLikeThisQueryDescriptor<object>>))]
1111
public interface IMoreLikeThisQuery : IQuery
1212
{
1313
[JsonProperty("analyzer")]

0 commit comments

Comments
 (0)