-
Notifications
You must be signed in to change notification settings - Fork 526
Expand file tree
/
Copy pathDefaultCosmosLinqSerializer.cs
More file actions
117 lines (102 loc) · 5.44 KB
/
DefaultCosmosLinqSerializer.cs
File metadata and controls
117 lines (102 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace Microsoft.Azure.Cosmos.Linq
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.Serialization;
using Microsoft.Azure.Documents;
using Newtonsoft.Json;
internal class DefaultCosmosLinqSerializer : ICosmosLinqSerializer
{
private readonly CosmosLinqSerializerOptions LinqSerializerOptions;
public DefaultCosmosLinqSerializer(CosmosLinqSerializerOptions linqSerializerOptions)
{
this.LinqSerializerOptions = linqSerializerOptions;
}
public bool RequiresCustomSerialization(MemberExpression memberExpression, Type memberType)
{
// There are two ways to specify a custom attribute
// 1- by specifying the JsonConverterAttribute on a Class/Enum
// [JsonConverter(typeof(StringEnumConverter))]
// Enum MyEnum
// {
// ...
// }
//
// 2- by specifying the JsonConverterAttribute on a property
// class MyClass
// {
// [JsonConverter(typeof(StringEnumConverter))]
// public MyEnum MyEnum;
// }
//
// Newtonsoft gives high precedence to the attribute specified
// on a property over on a type (class/enum)
// so we check both attributes and apply the same precedence rules
// JsonConverterAttribute doesn't allow duplicates so it's safe to
// use FirstOrDefault()
CustomAttributeData memberAttribute = memberExpression.Member.CustomAttributes.FirstOrDefault(ca => ca.AttributeType == typeof(Newtonsoft.Json.JsonConverterAttribute));
CustomAttributeData typeAttribute = memberType.GetsCustomAttributes().FirstOrDefault(ca => ca.AttributeType == typeof(Newtonsoft.Json.JsonConverterAttribute));
return memberAttribute != null || typeAttribute != null;
}
public string Serialize(object value, MemberExpression memberExpression, Type memberType)
{
CustomAttributeData memberAttribute = memberExpression.Member.CustomAttributes.FirstOrDefault(ca => ca.AttributeType == typeof(Newtonsoft.Json.JsonConverterAttribute));
CustomAttributeData typeAttribute = memberType.GetsCustomAttributes().FirstOrDefault(ca => ca.AttributeType == typeof(Newtonsoft.Json.JsonConverterAttribute));
CustomAttributeData converterAttribute = memberAttribute ?? typeAttribute;
Debug.Assert(converterAttribute.ConstructorArguments.Count > 0, $"{nameof(DefaultCosmosLinqSerializer)} Assert!", "At least one constructor argument exists.");
Type converterType = (Type)converterAttribute.ConstructorArguments[0].Value;
string serializedValue = converterType.GetConstructor(Type.EmptyTypes) != null
? JsonConvert.SerializeObject(value, (Newtonsoft.Json.JsonConverter)Activator.CreateInstance(converterType))
: JsonConvert.SerializeObject(value);
return serializedValue;
}
public string SerializeScalarExpression(ConstantExpression inputExpression)
{
return JsonConvert.SerializeObject(inputExpression.Value);
}
public string SerializeMemberName(MemberInfo memberInfo)
{
string memberName = null;
// Check if Newtonsoft JsonExtensionDataAttribute is present on the member, if so, return empty member name.
Newtonsoft.Json.JsonExtensionDataAttribute jsonExtensionDataAttribute = memberInfo.GetCustomAttribute<Newtonsoft.Json.JsonExtensionDataAttribute>(true);
if (jsonExtensionDataAttribute != null && jsonExtensionDataAttribute.ReadData)
{
return null;
}
// Json.Net honors JsonPropertyAttribute more than DataMemberAttribute
// So we check for JsonPropertyAttribute first.
JsonPropertyAttribute jsonPropertyAttribute = memberInfo.GetCustomAttribute<JsonPropertyAttribute>(true);
if (jsonPropertyAttribute != null && !string.IsNullOrEmpty(jsonPropertyAttribute.PropertyName))
{
memberName = jsonPropertyAttribute.PropertyName;
}
else
{
DataContractAttribute dataContractAttribute = memberInfo.DeclaringType.GetCustomAttribute<DataContractAttribute>(true);
if (dataContractAttribute != null)
{
DataMemberAttribute dataMemberAttribute = memberInfo.GetCustomAttribute<DataMemberAttribute>(true);
if (dataMemberAttribute != null && !string.IsNullOrEmpty(dataMemberAttribute.Name))
{
memberName = dataMemberAttribute.Name;
}
}
}
if (memberName == null)
{
memberName = memberInfo.Name;
}
if (this.LinqSerializerOptions != null)
{
memberName = CosmosSerializationUtil.GetStringWithPropertyNamingPolicy(this.LinqSerializerOptions, memberName);
}
return memberName;
}
}
}