diff --git a/FSharp.Json.Tests/Collections.fs b/FSharp.Json.Tests/Collections.fs index e36bb85..1e770ff 100644 --- a/FSharp.Json.Tests/Collections.fs +++ b/FSharp.Json.Tests/Collections.fs @@ -18,6 +18,13 @@ module Collections = let actual = Json.serializeU value Assert.AreEqual(expected, actual) + [] + let ``ResizeArray serialization to JSON array`` () = + let expected = """["some","text"]""" + let value = [ "some"; "text" ] |> ResizeArray + let actual = Json.serializeU value + Assert.AreEqual(expected, actual) + [] let ``Array serialization/deserialization`` () = let expected = [|"some"; "text"|] @@ -32,6 +39,13 @@ module Collections = let actual = Json.deserialize json Assert.AreEqual(expected, actual) + [] + let ``ResizeArray serialization/deserialization`` () = + let expected = [ "some"; "text" ] |> ResizeArray + let json = Json.serialize (expected) + let actual = Json.deserialize> json + Assert.AreEqual(expected, actual) + [] let ``Array empty serialization/deserialization`` () = let expected = [||] @@ -45,3 +59,10 @@ module Collections = let json = Json.serialize(expected) let actual = Json.deserialize json Assert.AreEqual(expected, actual) + + [] + let ``ResizeArray empty serialization/deserialization`` () = + let expected = ResizeArray() + let json = Json.serialize (expected) + let actual = Json.deserialize> json + Assert.AreEqual(expected, actual) diff --git a/FSharp.Json/Core.fs b/FSharp.Json/Core.fs index 6b7af4f..f2ed0a1 100644 --- a/FSharp.Json/Core.fs +++ b/FSharp.Json/Core.fs @@ -147,7 +147,7 @@ module internal Core = JsonValue.String ((value :?> Guid).ToString()) | t when t.IsEnum -> serializeEnum t jsonField value - | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t -> + | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t -> serialize config t value | _ -> failSerialization <| sprintf "Unknown type: %s" t.Name | true -> @@ -263,6 +263,7 @@ module internal Core = | t when isList t -> serializeEnumerable (value :?> IEnumerable) | t when isTuple t -> serializeTupleItems (getTupleElements t) (FSharpValue.GetTupleFields value) | t when isUnion t -> serializeUnion t value + | t when isResizeArray t -> serializeEnumerable (value :?> IEnumerable) | t -> let msg = sprintf "Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s." t.Name failSerialization msg @@ -370,7 +371,7 @@ module internal Core = JsonValueHelpers.getGuid path jvalue :> obj | t when t.IsEnum -> deserializeEnum path t jsonField jvalue - | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t -> + | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t -> deserialize config path t jvalue | _ -> failDeserialization path <| sprintf "Not supported type: %s" t.Name transformFromTargetType jsonField.Transform jvalue @@ -427,6 +428,19 @@ module internal Core = arrayValues |> List.ofSeq |> createList itemType | _ -> failDeserialization path "Failed to parse list from JSON that is not array." + let deserializeResizeArray (path: JsonPath) (t: Type) (jvalue: JsonValue) : obj = + match jvalue with + | JsonValue.Array jvalues -> + let itemType = getResizeArrayItemType t + + let arrayValues = + deserializeArrayItems path itemType jvalues + + arrayValues + |> List.ofSeq + |> createResizeArray itemType + | _ -> failDeserialization path "Failed to parse resize array from JSON that is not array." + let deserializeArray (path: JsonPath) (t: Type) (jvalue: JsonValue): obj = match jvalue with | JsonValue.Array jvalues -> @@ -545,5 +559,5 @@ module internal Core = | t when isList t -> deserializeList path t jvalue | t when isTuple t -> deserializeTuple path t jvalue | t when isUnion t -> deserializeUnion path t jvalue + | t when isResizeArray t -> deserializeResizeArray path t jvalue | _ -> failDeserialization path <| sprintf "Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s." t.Name - \ No newline at end of file diff --git a/FSharp.Json/Reflection.fs b/FSharp.Json/Reflection.fs index 9a6f789..1312545 100644 --- a/FSharp.Json/Reflection.fs +++ b/FSharp.Json/Reflection.fs @@ -35,6 +35,19 @@ module internal Reflection = let getListEmptyProperty_ (t: Type) = t.GetProperty("Empty") + let isResizeArray_ (t: Type) = + t.IsGenericType + && t.GetGenericTypeDefinition() = typedefof> + + let getResizeArrayType_ (itemType: Type) = + typedefof>.MakeGenericType ([| itemType |]) + + let getResizeArrayItemType_ (t: Type) = t.GetGenericArguments().[0] + + let getResizeArrayConstructor_ (t: Type) = t.GetConstructor([||]) + + let getResizeArrayAdd_ (t: Type) = t.GetMethod("Add") + let isMap_ (t: Type) = t.IsGenericType && t.GetGenericTypeDefinition() = typedefof> @@ -72,6 +85,13 @@ module internal Reflection = let getListConstructor: Type -> MethodInfo = getListConstructor_ |> cacheResult let getListEmptyProperty: Type -> PropertyInfo = getListEmptyProperty_ |> cacheResult + let isResizeArray : Type -> bool = isResizeArray_ |> cacheResult + let getResizeArrayType : Type -> Type = getResizeArrayType_ |> cacheResult + let getResizeArrayItemType : Type -> Type = getResizeArrayItemType_ |> cacheResult + let getResizeArrayAdd : Type -> MethodInfo = getResizeArrayAdd_ |> cacheResult + let getResizeArrayConstructor : Type -> ConstructorInfo = + getResizeArrayConstructor_ |> cacheResult + let isMap: Type -> bool = isMap_ |> cacheResult let getMapKeyType: Type -> Type = getMapKeyType_ |> cacheResult let getMapValueType: Type -> Type = getMapValueType_ |> cacheResult @@ -98,6 +118,22 @@ module internal Reflection = let theList = (getListEmptyProperty listType).GetValue(null) List.foldBack addItem items theList + let createResizeArray (itemType: Type) (items: obj list) = + let resizeArrayType = getResizeArrayType itemType + + let resizeArrayAdd resizeArray item = + (getResizeArrayAdd resizeArrayType) + .Invoke(resizeArray, [| item |]) + |> ignore + + resizeArray + + let newResizeArray = + (getResizeArrayConstructor resizeArrayType) + .Invoke([||]) + + List.fold resizeArrayAdd newResizeArray items + let KvpKey (value: obj): obj = let keyProperty = value.GetType().GetProperty("Key") keyProperty.GetValue(value, null) diff --git a/README.md b/README.md index 83d632e..1dcabee 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ option | option is not represented by itself
`None` value might be represente tuple | list record | object map | object -array
list | list +array
list
ResizeArray | list union | object with special structure
read more in [Unions](#unions) section obj | read [Untyped Data](#untyped-data) section