8eef1168b7ba7fb18f561a53ef3b2b6235404d04
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Collections;
6 using System.Diagnostics;
7 using System.Text.Json.Serialization.Converters;
8
9 namespace System.Text.Json
10 {
11     public static partial class JsonSerializer
12     {
13         private static void HandleStartDictionary(JsonSerializerOptions options, ref ReadStack state)
14         {
15             Debug.Assert(!state.Current.IsProcessingEnumerable());
16
17             JsonPropertyInfo jsonPropertyInfo = state.Current.JsonPropertyInfo;
18             if (jsonPropertyInfo == null)
19             {
20                 jsonPropertyInfo = state.Current.JsonClassInfo.CreateRootObject(options);
21             }
22
23             Debug.Assert(jsonPropertyInfo != null);
24
25             // A nested object or dictionary so push new frame.
26             if (state.Current.CollectionPropertyInitialized)
27             {
28                 state.Push();
29                 state.Current.JsonClassInfo = jsonPropertyInfo.ElementClassInfo;
30                 state.Current.InitializeJsonPropertyInfo();
31                 state.Current.CollectionPropertyInitialized = true;
32
33                 ClassType classType = state.Current.JsonClassInfo.ClassType;
34                 if (classType == ClassType.Value)
35                 {
36                     Type elementClassInfoType = jsonPropertyInfo.ElementClassInfo.Type;
37                     if (elementClassInfoType != typeof(object) && elementClassInfoType != typeof(JsonElement))
38                     {
39                         ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(state.Current.JsonClassInfo.Type);
40                     }
41                 }
42
43                 JsonClassInfo classInfo = state.Current.JsonClassInfo;
44
45                 if (state.Current.IsProcessingIDictionaryConstructible())
46                 {
47                     state.Current.TempDictionaryValues = (IDictionary)classInfo.CreateConcreteDictionary();
48                 }
49                 else
50                 {
51                     if (classInfo.CreateObject == null)
52                     {
53                         ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(classInfo.Type);
54                         return;
55                     }
56                     state.Current.ReturnValue = classInfo.CreateObject();
57                 }
58
59                 return;
60             }
61
62             state.Current.CollectionPropertyInitialized = true;
63
64             if (state.Current.IsProcessingIDictionaryConstructible())
65             {
66                 JsonClassInfo dictionaryClassInfo;
67                 if (jsonPropertyInfo.DeclaredPropertyType == jsonPropertyInfo.ImplementedPropertyType)
68                 {
69                     dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.RuntimePropertyType);
70                 }
71                 else
72                 {
73                     dictionaryClassInfo = options.GetOrAddClass(jsonPropertyInfo.DeclaredPropertyType);
74                 }
75
76                 state.Current.TempDictionaryValues = (IDictionary)dictionaryClassInfo.CreateConcreteDictionary();
77             }
78             else
79             {
80                 // Create the dictionary.
81                 JsonClassInfo dictionaryClassInfo = jsonPropertyInfo.RuntimeClassInfo;
82                 IDictionary value = (IDictionary)dictionaryClassInfo.CreateObject();
83
84                 if (value != null)
85                 {
86                     if (state.Current.ReturnValue != null)
87                     {
88                         state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, value);
89                     }
90                     else
91                     {
92                         // A dictionary is being returned directly, or a nested dictionary.
93                         state.Current.SetReturnValue(value);
94                     }
95                 }
96             }
97         }
98
99         private static void HandleEndDictionary(JsonSerializerOptions options, ref ReadStack state)
100         {
101             Debug.Assert(!state.Current.SkipProperty);
102
103             if (state.Current.IsProcessingProperty(ClassType.Dictionary))
104             {
105                 // Handle special case of DataExtensionProperty where we just added a dictionary element to the extension property.
106                 // Since the JSON value is not a dictionary element (it's a normal property in JSON) a JsonTokenType.EndObject
107                 // encountered here is from the outer object so forward to HandleEndObject().
108                 if (state.Current.JsonClassInfo.DataExtensionProperty == state.Current.JsonPropertyInfo)
109                 {
110                     HandleEndObject(ref state);
111                 }
112                 else
113                 {
114                     // We added the items to the dictionary already.
115                     state.Current.EndProperty();
116                 }
117             }
118             else if (state.Current.IsProcessingProperty(ClassType.IDictionaryConstructible))
119             {
120                 Debug.Assert(state.Current.TempDictionaryValues != null);
121                 JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
122                 state.Current.JsonPropertyInfo.SetValueAsObject(state.Current.ReturnValue, converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options));
123                 state.Current.EndProperty();
124             }
125             else
126             {
127                 object value;
128                 if (state.Current.TempDictionaryValues != null)
129                 {
130                     JsonDictionaryConverter converter = state.Current.JsonPropertyInfo.DictionaryConverter;
131                     value = converter.CreateFromDictionary(ref state, state.Current.TempDictionaryValues, options);
132                 }
133                 else
134                 {
135                     value = state.Current.ReturnValue;
136                 }
137
138                 if (state.IsLastFrame)
139                 {
140                     // Set the return value directly since this will be returned to the user.
141                     state.Current.Reset();
142                     state.Current.ReturnValue = value;
143                 }
144                 else
145                 {
146                     state.Pop();
147                     ApplyObjectToEnumerable(value, ref state);
148                 }
149             }
150         }
151     }
152 }