@@ -62,28 +62,51 @@ module internal Core =
6262 let valueType = value.GetType()
6363 ( valueType, value)
6464
65+ let getEnumMode ( config : JsonConfig ) ( jsonField : JsonField ) =
66+ match jsonField.EnumValue with
67+ | EnumMode.Default ->
68+ match config.enumValue with
69+ | EnumMode.Default -> EnumMode.Name
70+ | m -> m
71+ | m -> m
72+
6573 let failSerialization ( message : string ) =
6674 raise ( new JsonSerializationError( message))
6775
6876 let rec serialize ( config : JsonConfig ) ( t : Type ) ( value : obj ): JsonValue =
6977 let serializeEnum ( t : Type ) ( jsonField : JsonField ) ( value : obj ): JsonValue =
70- match jsonField.EnumValue with
78+ let baseT = Enum.GetUnderlyingType t
79+ let enumMode = getEnumMode config jsonField
80+ match enumMode with
7181 | EnumMode.Value ->
72- let index = decimal ( value :?> int)
73- JsonValue.Number index
82+ match baseT with
83+ | t when t = typeof< int> ->
84+ let enumValue = decimal ( value :?> int)
85+ JsonValue.Number enumValue
86+ | t when t = typeof< byte> ->
87+ let enumValue = decimal ( value :?> byte)
88+ JsonValue.Number enumValue
89+ | t when t = typeof< char> ->
90+ let enumValue = sprintf " %c " ( value :?> char)
91+ JsonValue.String enumValue
7492 | EnumMode.Name ->
7593 let strvalue = Enum.GetName( t, value)
7694 JsonValue.String strvalue
7795 | mode -> failSerialization <| sprintf " Failed to serialize enum %s , unsupported enum mode: %A " t.Name mode
7896
97+ let getUntypedType ( t : Type ) ( value : obj ): Type =
98+ if t = typeof< obj> then
99+ if config.allowUntyped then
100+ value.GetType()
101+ else
102+ failSerialization <| " Failed to serialize untyped data, allowUntyped set to false"
103+ else t
104+
79105 let serializeNonOption ( t : Type ) ( jsonField : JsonField ) ( value : obj ): JsonValue =
80106 match jsonField.AsJson with
81107 | false ->
82108 let t , value = transformToTargetType t value jsonField.Transform
83- let t =
84- if t = typeof< obj> then
85- value.GetType()
86- else t
109+ let t = getUntypedType t value
87110 match t with
88111 | t when t = typeof< int> ->
89112 JsonValue.Number ( decimal ( value :?> int))
@@ -97,6 +120,8 @@ module internal Core =
97120 JsonValue.Boolean ( value :?> bool)
98121 | t when t = typeof< string> ->
99122 JsonValue.String ( value :?> string)
123+ | t when t = typeof< char> ->
124+ JsonValue.String ( string( value :?> char))
100125 | t when t = typeof< DateTime> ->
101126 JsonValue.String (( value :?> DateTime) .ToString( jsonField.DateTimeFormat))
102127 | t when t = typeof< DateTimeOffset> ->
@@ -127,6 +152,15 @@ module internal Core =
127152 | Omit -> None
128153 | _ -> Some ( serializeNonOption t jsonField value)
129154
155+ let serializeUnwrapOptionWithNull ( t : Type ) ( jsonField : JsonField ) ( value : obj ): JsonValue =
156+ match t with
157+ | t when isOption t ->
158+ let unwrapedValue = unwrapOption t value
159+ match unwrapedValue with
160+ | Some value -> serializeNonOption ( getOptionType t) jsonField value
161+ | None -> JsonValue.Null
162+ | _ -> serializeNonOption t jsonField value
163+
130164 let serializeProperty ( therec : obj ) ( prop : PropertyInfo ): ( string * JsonValue ) option =
131165 let jsonField = getJsonFieldProperty prop
132166 let propValue = prop.GetValue( therec, Array.empty)
@@ -139,7 +173,17 @@ module internal Core =
139173 let serializeEnumerable ( values : IEnumerable ): JsonValue =
140174 let items =
141175 values.Cast< Object>()
142- |> Seq.map ( fun value -> serializeUnwrapOption ( value.GetType()) JsonField.Default value)
176+ |> Seq.map ( fun value ->
177+ serializeUnwrapOption ( value.GetType()) JsonField.Default value)
178+ |> Seq.map ( someOrDefault JsonValue.Null)
179+ items |> Array.ofSeq |> JsonValue.Array
180+
181+ let serializeTupleItems ( types : Type seq ) ( values : IEnumerable ): JsonValue =
182+ let items =
183+ values.Cast< Object>()
184+ |> Seq.zip types
185+ |> Seq.map ( fun ( t , value ) ->
186+ serializeUnwrapOption t JsonField.Default value)
143187 |> Seq.map ( someOrDefault JsonValue.Null)
144188 items |> Array.ofSeq |> JsonValue.Array
145189
@@ -162,13 +206,15 @@ module internal Core =
162206 let serializeUnion ( t : Type ) ( theunion : obj ): JsonValue =
163207 let caseInfo , values = FSharpValue.GetUnionFields( theunion, t)
164208 let jsonField = getJsonFieldUnionCase caseInfo
209+ let types = caseInfo.GetFields() |> Array.map ( fun p -> p.PropertyType)
165210 let jvalue =
166211 match values.Length with
167212 | 1 ->
168213 let caseValue = values.[ 0 ]
169- serializeNonOption ( caseValue.GetType()) jsonField caseValue
214+ let caseType = types.[ 0 ]
215+ serializeUnwrapOptionWithNull caseType jsonField caseValue
170216 | _ ->
171- serializeEnumerable values
217+ serializeTupleItems types values
172218 let unionCases = getUnionCases caseInfo.DeclaringType
173219 match unionCases.Length with
174220 | 1 -> jvalue
@@ -189,7 +235,7 @@ module internal Core =
189235 | t when isMap t -> serializeKvpEnumerable ( value :?> IEnumerable)
190236 | t when isArray t -> serializeEnumerable ( value :?> IEnumerable)
191237 | t when isList t -> serializeEnumerable ( value :?> IEnumerable)
192- | t when isTuple t -> serializeEnumerable ( FSharpValue.GetTupleFields value)
238+ | t when isTuple t -> serializeTupleItems ( getTupleElements t ) ( FSharpValue.GetTupleFields value)
193239 | t when isUnion t -> serializeUnion t value
194240 | t ->
195241 let msg = sprintf " Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s ." t.Name
@@ -221,15 +267,34 @@ module internal Core =
221267
222268 let rec deserialize ( config : JsonConfig ) ( path : JsonPath ) ( t : Type ) ( jvalue : JsonValue ): obj =
223269 let deserializeEnum ( path : JsonPath ) ( t : Type ) ( jsonField : JsonField ) ( jvalue : JsonValue ): obj =
224- match jsonField.EnumValue with
270+ let baseT = Enum.GetUnderlyingType t
271+ let enumMode = getEnumMode config jsonField
272+ match enumMode with
225273 | EnumMode.Value ->
226- let index = JsonValueHelpers.getInt path jvalue
227- Enum.ToObject( t, index)
274+ match baseT with
275+ | baseT when baseT = typeof< int> ->
276+ let enumValue = JsonValueHelpers.getInt path jvalue
277+ Enum.ToObject( t, enumValue)
278+ | baseT when baseT = typeof< byte> ->
279+ let enumValue = JsonValueHelpers.getByte path jvalue
280+ Enum.ToObject( t, enumValue)
281+ | baseT when baseT = typeof< char> ->
282+ let enumValue = JsonValueHelpers.getChar path jvalue
283+ Enum.ToObject( t, enumValue)
228284 | EnumMode.Name ->
229285 let valueStr = JsonValueHelpers.getString path jvalue
230286 Enum.Parse( t, valueStr)
231287 | mode -> failDeserialization path <| sprintf " Failed to deserialize enum %s , unsupported enum mode: %A " t.Name mode
232288
289+ let getUntypedType ( path : JsonPath ) ( t : Type ) ( jvalue : JsonValue ): Type =
290+ match t with
291+ | t when t = typeof< obj> ->
292+ if config.allowUntyped then
293+ getJsonValueType jvalue
294+ else
295+ failDeserialization path <| sprintf " Failed to deserialize object, allowUntyped set to false"
296+ | t -> t
297+
233298 let deserializeNonOption ( path : JsonPath ) ( t : Type ) ( jsonField : JsonField ) ( jvalue : JsonValue ): obj =
234299 match jsonField.AsJson with
235300 | true ->
@@ -238,10 +303,7 @@ module internal Core =
238303 | _ -> jvalue.ToString( JsonSaveOptions.DisableFormatting) :> obj
239304 | false ->
240305 let t = getTargetType t jsonField
241- let t =
242- match t with
243- | t when t = typeof< obj> -> getJsonValueType jvalue
244- | t -> t
306+ let t = getUntypedType path t jvalue
245307 let jvalue =
246308 match t with
247309 | t when t = typeof< int> ->
@@ -256,6 +318,8 @@ module internal Core =
256318 JsonValueHelpers.getBool path jvalue :> obj
257319 | t when t = typeof< string> ->
258320 JsonValueHelpers.getString path jvalue :> obj
321+ | t when t = typeof< char> ->
322+ JsonValueHelpers.getChar path jvalue :> obj
259323 | t when t = typeof< DateTime> ->
260324 JsonValueHelpers.getDateTime CultureInfo.InvariantCulture path jvalue :> obj
261325 | t when t = typeof< DateTimeOffset> ->
0 commit comments