Skip to content

Commit d6e598a

Browse files
russcamMpdreamz
authored andcommitted
DeserializeAsync behaviour consistent with its generic counterpart (#3058)
Cache compiled expressions for resolving default(T) from a Type Remove virtual from methods of InternalSerializer. Users cannot derive from this internal type any more.
1 parent 0781aaf commit d6e598a

File tree

2 files changed

+40
-23
lines changed

2 files changed

+40
-23
lines changed

src/Nest/CommonAbstractions/Extensions/TypeExtensions.cs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ internal static class TypeExtensions
1515
private static readonly MethodInfo GetActivatorMethodInfo =
1616
typeof(TypeExtensions).GetMethod(nameof(GetActivator), BindingFlags.Static | BindingFlags.NonPublic);
1717

18+
private static readonly ConcurrentDictionary<Type, Func<object>> CachedDefaultValues =
19+
new ConcurrentDictionary<Type, Func<object>>();
20+
1821
private static readonly ConcurrentDictionary<string, ObjectActivator<object>> CachedActivators =
1922
new ConcurrentDictionary<string, ObjectActivator<object>>();
2023

@@ -29,17 +32,14 @@ internal static class TypeExtensions
2932

3033
private delegate T ObjectActivator<out T>(params object[] args);
3134

32-
internal static object CreateGenericInstance(this Type t, Type closeOver, params object[] args)
33-
{
34-
return t.CreateGenericInstance(new[] {closeOver}, args);
35-
}
35+
internal static object CreateGenericInstance(this Type t, Type closeOver, params object[] args) =>
36+
t.CreateGenericInstance(new[] {closeOver}, args);
3637

3738
internal static object CreateGenericInstance(this Type t, Type[] closeOver, params object[] args)
3839
{
3940
var argKey = closeOver.Aggregate(new StringBuilder(), (sb, gt) => sb.Append("--" + gt.FullName), sb => sb.ToString());
4041
var key = t.FullName + argKey;
41-
Type closedType;
42-
if (!CachedGenericClosedTypes.TryGetValue(key, out closedType))
42+
if (!CachedGenericClosedTypes.TryGetValue(key, out var closedType))
4343
{
4444
closedType = t.MakeGenericType(closeOver);
4545
CachedGenericClosedTypes.TryAdd(key, closedType);
@@ -71,6 +71,15 @@ internal static object CreateInstance(this Type t, params object[] args)
7171
return activator(args);
7272
}
7373

74+
internal static object DefaultValue(this Type type) =>
75+
type.IsValueType()
76+
? CachedDefaultValues.GetOrAdd(type, t =>
77+
Expression.Lambda<Func<object>>(
78+
Expression.Convert(Expression.Default(type), typeof(object))
79+
).Compile()
80+
).Invoke()
81+
: null;
82+
7483
//do not remove this is referenced through GetActivatorMethod
7584
private static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
7685
{
@@ -88,11 +97,8 @@ private static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
8897
{
8998
var index = Expression.Constant(i);
9099
var paramType = paramsInfo[i].ParameterType;
91-
92100
var paramAccessorExp = Expression.ArrayIndex(param, index);
93-
94101
var paramCastExp = Expression.Convert(paramAccessorExp, paramType);
95-
96102
argsExp[i] = paramCastExp;
97103
}
98104

@@ -125,8 +131,7 @@ internal static IList<JsonProperty> GetCachedObjectProperties(this Type t,
125131

126132
internal static IList<PropertyInfo> AllPropertiesCached(this Type t)
127133
{
128-
IList<PropertyInfo> propertyInfos;
129-
if (CachedTypePropertyInfos.TryGetValue(t, out propertyInfos))
134+
if (CachedTypePropertyInfos.TryGetValue(t, out var propertyInfos))
130135
return propertyInfos;
131136
propertyInfos = t.AllPropertiesNotCached().ToList();
132137
CachedTypePropertyInfos.TryAdd(t, propertyInfos);

src/Nest/CommonAbstractions/SerializationBehavior/InternalSerializer.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.IO;
4+
using System.Linq.Expressions;
35
using System.Text;
46
using System.Threading;
57
using System.Threading.Tasks;
@@ -14,6 +16,10 @@ namespace Nest
1416
internal class InternalSerializer : IElasticsearchSerializer
1517
{
1618
private static readonly Encoding ExpectedEncoding = new UTF8Encoding(false);
19+
20+
//we still support net45 so Task.Completed is not available
21+
private static readonly Task CompletedTask = Task.FromResult(false);
22+
1723
private readonly JsonSerializer _indentedSerializer;
1824
internal JsonSerializer Serializer { get; }
1925

@@ -66,8 +72,7 @@ public virtual void Serialize<T>(T data, Stream writableStream, SerializationFor
6672
}
6773
}
6874

69-
//we still support net45 so Task.Completed is not available
70-
private static readonly Task CompletedTask = Task.FromResult(false);
75+
7176
public Task SerializeAsync<T>(T data, Stream stream, SerializationFormatting formatting = SerializationFormatting.Indented,
7277
CancellationToken cancellationToken = default(CancellationToken))
7378
{
@@ -77,13 +82,11 @@ public Task SerializeAsync<T>(T data, Stream stream, SerializationFormatting for
7782
return CompletedTask;
7883
}
7984

80-
public object Default(Type type) => type.IsValueType() ? type.CreateInstance() : null;
81-
82-
public virtual T Deserialize<T>(Stream stream) => (T) this.Deserialize(typeof(T), stream);
85+
public T Deserialize<T>(Stream stream) => (T) this.Deserialize(typeof(T), stream);
8386

84-
public virtual object Deserialize(Type type, Stream stream)
87+
public object Deserialize(Type type, Stream stream)
8588
{
86-
if (stream == null) return Default(type);
89+
if (stream == null) return type.DefaultValue();
8790
using (var streamReader = new StreamReader(stream))
8891
using (var jsonTextReader = new JsonTextReader(streamReader))
8992
{
@@ -92,8 +95,9 @@ public virtual object Deserialize(Type type, Stream stream)
9295
}
9396
}
9497

95-
public virtual async Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
98+
public async Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
9699
{
100+
if (stream == null) return default(T);
97101
using (var streamReader = new StreamReader(stream))
98102
using (var jsonTextReader = new JsonTextReader(streamReader))
99103
{
@@ -108,18 +112,26 @@ public virtual object Deserialize(Type type, Stream stream)
108112
}
109113
catch
110114
{
111-
return await Task.FromResult(default(T)).ConfigureAwait(false);
115+
return default(T);
112116
}
113117
}
114118
}
115119

116-
public virtual async Task<object> DeserializeAsync(Type type, Stream stream, CancellationToken cancellationToken = default(CancellationToken))
120+
public async Task<object> DeserializeAsync(Type type, Stream stream, CancellationToken cancellationToken = default(CancellationToken))
117121
{
122+
if (stream == null) return type.DefaultValue();
118123
using (var streamReader = new StreamReader(stream))
119124
using (var jsonTextReader = new JsonTextReader(streamReader))
120125
{
121-
var token = await JToken.LoadAsync(jsonTextReader, cancellationToken).ConfigureAwait(false);
122-
return token.ToObject(type, this.Serializer);
126+
try
127+
{
128+
var token = await JToken.LoadAsync(jsonTextReader, cancellationToken).ConfigureAwait(false);
129+
return token.ToObject(type, this.Serializer);
130+
}
131+
catch
132+
{
133+
return type.DefaultValue();
134+
}
123135
}
124136
}
125137

0 commit comments

Comments
 (0)